More API function tests...
[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   {
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                                          NULL /* no shorten */,
487                                          &result_processor,
488                                          request);
489   }
490   else
491   {
492     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493                 "Using DNS resolver IP `%s' to resolve `%s'\n",
494                 dns_ip,
495                 name);
496     GNUNET_DNSPARSER_free_packet (request->packet);
497     request->packet = NULL;
498     request->dns_lookup = GNUNET_DNSSTUB_resolve2 (dns_stub,
499                                                    udp_msg,
500                                                    udp_msg_size,
501                                                    &dns_result_processor,
502                                                    request);
503   }
504   GNUNET_free (name);
505 }
506
507
508 /**
509  * Task to read IPv4 DNS packets.
510  *
511  * @param cls the 'listen_socket4'
512  */
513 static void
514 read_dns4 (void *cls)
515 {
516   struct sockaddr_in v4;
517   socklen_t addrlen;
518   ssize_t size;
519   const struct GNUNET_SCHEDULER_TaskContext *tc;
520
521   GNUNET_assert (listen_socket4 == cls);
522   t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
523                                       listen_socket4,
524                                       &read_dns4,
525                                       listen_socket4);
526   tc = GNUNET_SCHEDULER_get_task_context ();
527   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
528     return; /* shutdown? */
529   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
530   if (0 > size)
531     {
532       GNUNET_break (0);
533       return; /* read error!? */
534     }
535   {
536     char buf[size + 1];
537
538     addrlen = sizeof (v4);
539     GNUNET_break (size ==
540                   GNUNET_NETWORK_socket_recvfrom (listen_socket4,
541                                                   buf,
542                                                   size + 1,
543                                                   (struct sockaddr *) &v4,
544                                                   &addrlen));
545     handle_request (listen_socket4,
546                     &v4,
547                     addrlen,
548                     buf,
549                     size);
550   }
551 }
552
553
554 /**
555  * Task to read IPv6 DNS packets.
556  *
557  * @param cls the 'listen_socket6'
558  */
559 static void
560 read_dns6 (void *cls)
561 {
562   struct sockaddr_in6 v6;
563   socklen_t addrlen;
564   ssize_t size;
565   const struct GNUNET_SCHEDULER_TaskContext *tc;
566
567   GNUNET_assert (listen_socket6 == cls);
568   t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
569                                       listen_socket6,
570                                       &read_dns6,
571                                       listen_socket6);
572   tc = GNUNET_SCHEDULER_get_task_context ();
573   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
574     return; /* shutdown? */
575   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
576   if (0 > size)
577     {
578       GNUNET_break (0);
579       return; /* read error!? */
580     }
581   {
582     char buf[size];
583
584     addrlen = sizeof (v6);
585     GNUNET_break (size ==
586                   GNUNET_NETWORK_socket_recvfrom (listen_socket6,
587                                                   buf,
588                                                   size,
589                                                   (struct sockaddr *) &v6,
590                                                   &addrlen));
591     handle_request (listen_socket6, &v6, addrlen,
592                     buf, size);
593   }
594 }
595
596
597 /**
598  * Start DNS daemon.
599  */
600 static void
601 run_dnsd ()
602 {
603   if (NULL == dns_suffix)
604     dns_suffix = DNS_SUFFIX;
605   if (NULL == fcfs_suffix)
606     fcfs_suffix = FCFS_SUFFIX;
607   if (NULL == (gns = GNUNET_GNS_connect (cfg)))
608     return;
609   if (NULL == (dns_stub = GNUNET_DNSSTUB_start (dns_ip)))
610   {
611     GNUNET_GNS_disconnect (gns);
612     gns = NULL;
613     return;
614   }
615   listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
616                                                  SOCK_DGRAM,
617                                                  IPPROTO_UDP);
618   if (NULL != listen_socket4)
619   {
620     struct sockaddr_in v4;
621     
622     memset (&v4, 0, sizeof (v4));
623     v4.sin_family = AF_INET;
624 #if HAVE_SOCKADDR_IN_SIN_LEN
625     v4.sin_len = sizeof (v4);
626 #endif
627     v4.sin_port = htons (listen_port);
628     if (GNUNET_OK !=
629         GNUNET_NETWORK_socket_bind (listen_socket4,
630                                     (struct sockaddr *) &v4,
631                                     sizeof (v4)))
632     {
633       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
634       GNUNET_NETWORK_socket_close (listen_socket4);
635       listen_socket4 = NULL;
636     }
637   }
638   listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
639                                                 SOCK_DGRAM,
640                                                 IPPROTO_UDP);
641   if (NULL != listen_socket6)
642   {
643     struct sockaddr_in6 v6;
644     
645     memset (&v6, 0, sizeof (v6));
646     v6.sin6_family = AF_INET6;
647 #if HAVE_SOCKADDR_IN_SIN_LEN
648     v6.sin6_len = sizeof (v6);
649 #endif
650     v6.sin6_port = htons (listen_port);
651     if (GNUNET_OK !=
652         GNUNET_NETWORK_socket_bind (listen_socket6,
653                                     (struct sockaddr *) &v6,
654                                     sizeof (v6)))
655     {
656       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
657       GNUNET_NETWORK_socket_close (listen_socket6);
658       listen_socket6 = NULL;
659     }
660   }
661   if ( (NULL == listen_socket4) &&
662        (NULL == listen_socket6) )
663   {
664     GNUNET_GNS_disconnect (gns);
665     gns = NULL;
666     GNUNET_DNSSTUB_stop (dns_stub);
667     dns_stub = NULL;
668     return;
669   }
670   if (NULL != listen_socket4)
671     t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
672                                         listen_socket4,
673                                         &read_dns4,
674                                         listen_socket4);
675   if (NULL != listen_socket6)
676     t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
677                                         listen_socket6,
678                                         &read_dns6,
679                                         listen_socket6);
680 }
681
682
683 /**
684  * Method called to inform about the egos of this peer.
685  *
686  * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
687  * this function is only called ONCE, and 'NULL' being passed in
688  * @a ego does indicate an error (i.e. name is taken or no default
689  * value is known).  If @a ego is non-NULL and if '*ctx'
690  * is set in those callbacks, the value WILL be passed to a subsequent
691  * call to the identity callback of #GNUNET_IDENTITY_connect (if
692  * that one was not NULL).
693  *
694  * @param cls closure, NULL
695  * @param ego ego handle
696  * @param ctx context for application to store data for this ego
697  *                 (during the lifetime of this process, initially NULL)
698  * @param name name assigned by the user for this ego,
699  *                   NULL if the user just deleted the ego and it
700  *                   must thus no longer be used
701  */
702 static void
703 identity_cb (void *cls,
704              struct GNUNET_IDENTITY_Ego *ego,
705              void **ctx,
706              const char *name)
707 {
708   id_op = NULL;
709   if (NULL == ego)
710   {
711     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
712                 _("No ego configured for `dns2gns` subsystem\n"));
713     return;
714   }
715   GNUNET_IDENTITY_ego_get_public_key (ego,
716                                       &my_zone);
717   run_dnsd ();
718 }
719
720
721 /**
722  * Main function that will be run.
723  *
724  * @param cls closure
725  * @param args remaining command-line arguments
726  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
727  * @param c configuration
728  */
729 static void
730 run (void *cls,
731      char *const *args,
732      const char *cfgfile,
733      const struct GNUNET_CONFIGURATION_Handle *c)
734 {
735   cfg = c;
736
737   if (NULL == dns_ip)
738   {
739     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
740                 _("No DNS server specified!\n"));
741     return;
742   }
743   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
744   if (NULL == gns_zone_str)
745     {
746       identity = GNUNET_IDENTITY_connect (cfg,
747                                           NULL, NULL);
748       id_op = GNUNET_IDENTITY_get (identity,
749                                    "dns2gns",
750                                    &identity_cb,
751                                    NULL);
752       return;
753     }
754   if ( (NULL == gns_zone_str) ||
755        (GNUNET_OK !=
756         GNUNET_CRYPTO_ecdsa_public_key_from_string (gns_zone_str,
757                                                     strlen (gns_zone_str),
758                                                     &my_zone)) )
759   {
760     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
761                 _("No valid GNS zone specified!\n"));
762     GNUNET_SCHEDULER_shutdown ();
763     return;
764   }
765   run_dnsd ();
766 }
767
768
769 /**
770  * The main function for the dns2gns daemon.
771  *
772  * @param argc number of arguments from the command line
773  * @param argv command line arguments
774  * @return 0 ok, 1 on error
775  */
776 int
777 main (int argc,
778       char *const *argv)
779 {
780   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
781     {'d', "dns", "IP",
782       gettext_noop ("IP of recursive DNS resolver to use (required)"), 1,
783       &GNUNET_GETOPT_set_string, &dns_ip},
784     {'f', "fcfs", "NAME",
785       gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"), 1,
786       &GNUNET_GETOPT_set_string, &fcfs_suffix},
787     {'s', "suffix", "SUFFIX",
788       gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"), 1,
789       &GNUNET_GETOPT_set_string, &dns_suffix},
790     {'p', "port", "UDPPORT",
791       gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"), 1,
792       &GNUNET_GETOPT_set_uint, &listen_port},
793     {'z', "zone", "PUBLICKEY",
794       gettext_noop ("Public key of the GNS zone to use (overrides default)"), 1,
795       &GNUNET_GETOPT_set_string, &gns_zone_str},
796     GNUNET_GETOPT_OPTION_END
797   };
798   int ret;
799
800   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
801                                                  &argc, &argv))
802     return 2;
803   GNUNET_log_setup ("gnunet-dns2gns", "WARNING", NULL);
804   ret =
805       (GNUNET_OK ==
806        GNUNET_PROGRAM_run (argc, argv, "gnunet-dns2gns",
807                            _("GNUnet DNS-to-GNS proxy (a DNS server)"),
808                            options,
809                            &run, NULL)) ? 0 : 1;
810   GNUNET_free ((void*) argv);
811   return ret;
812 }
813
814 /* end of gnunet-dns2gns.c */