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