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