-remove debug message
[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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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_dnsstub_lib.h>
30 #include "gns.h"
31
32 /**
33  * Timeout for DNS requests.
34  */
35 #define TIMEOUT GNUNET_TIME_UNIT_MINUTES
36
37 /**
38  * Data kept per request.
39  */
40 struct Request
41 {
42   /**
43    * Socket to use for sending the reply.
44    */
45   struct GNUNET_NETWORK_Handle *lsock;
46
47   /**
48    * Destination address to use.
49    */
50   const void *addr;
51
52   /**
53    * Initially, this is the DNS request, it will then be
54    * converted to the DNS response.
55    */
56   struct GNUNET_DNSPARSER_Packet *packet;
57
58   /**
59    * Our GNS request handle.
60    */
61   struct GNUNET_GNS_LookupWithTldRequest *lookup;
62
63   /**
64    * Our DNS request handle
65    */
66   struct GNUNET_DNSSTUB_RequestSocket *dns_lookup;
67
68   /**
69    * Task run on timeout or shutdown to clean up without
70    * response.
71    */
72   struct GNUNET_SCHEDULER_Task *timeout_task;
73
74   /**
75    * Original UDP request message.
76    */
77   char *udp_msg;
78
79   /**
80    * Number of bytes in @e addr.
81    */
82   size_t addr_len;
83
84   /**
85    * Number of bytes in @e udp_msg.
86    */
87   size_t udp_msg_size;
88
89   /**
90    * ID of the original request.
91    */
92   uint16_t original_request_id;
93 };
94
95 /**
96  * The address to bind to
97  */
98 static in_addr_t address;
99
100 /**
101  * The IPv6 address to bind to
102  */
103 static struct in6_addr address6;
104
105
106 /**
107  * Handle to GNS resolver.
108  */
109 struct GNUNET_GNS_Handle *gns;
110
111 /**
112  * Stub resolver
113  */
114 struct GNUNET_DNSSTUB_Context *dns_stub;
115
116 /**
117  * Listen socket for IPv4.
118  */
119 static struct GNUNET_NETWORK_Handle *listen_socket4;
120
121 /**
122  * Listen socket for IPv6.
123  */
124 static struct GNUNET_NETWORK_Handle *listen_socket6;
125
126 /**
127  * Task for IPv4 socket.
128  */
129 static struct GNUNET_SCHEDULER_Task *t4;
130
131 /**
132  * Task for IPv6 socket.
133  */
134 static struct GNUNET_SCHEDULER_Task *t6;
135
136 /**
137  * IP of DNS server
138  */
139 static char *dns_ip;
140
141 /**
142  * UDP Port we listen on for inbound DNS requests.
143  */
144 static unsigned int listen_port = 53;
145
146 /**
147  * Configuration to use.
148  */
149 static const struct GNUNET_CONFIGURATION_Handle *cfg;
150
151
152 /**
153  * Task run on shutdown.  Cleans up everything.
154  *
155  * @param cls unused
156  */
157 static void
158 do_shutdown (void *cls)
159 {
160   (void) cls;
161   if (NULL != t4)
162   {
163     GNUNET_SCHEDULER_cancel (t4);
164     t4 = NULL;
165   }
166   if (NULL != t6)
167   {
168     GNUNET_SCHEDULER_cancel (t6);
169     t6 = NULL;
170   }
171   if (NULL != listen_socket4)
172   {
173     GNUNET_NETWORK_socket_close (listen_socket4);
174     listen_socket4 = NULL;
175   }
176   if (NULL != listen_socket6)
177   {
178     GNUNET_NETWORK_socket_close (listen_socket6);
179     listen_socket6 = NULL;
180   }
181   if (NULL != gns)
182   {
183     GNUNET_GNS_disconnect (gns);
184     gns = NULL;
185   }
186   if (NULL != dns_stub)
187   {
188     GNUNET_DNSSTUB_stop (dns_stub);
189     dns_stub = NULL;
190   }
191 }
192
193 /**
194  * Shuffle answers
195  * Fisher-Yates (aka Knuth) Shuffle
196  *
197  * @param request context for the request (with answers)
198  */
199 static void
200 shuffle_answers (struct Request *request)
201 {
202   unsigned int idx = request->packet->num_answers;
203   unsigned int r_idx;
204   struct GNUNET_DNSPARSER_Record tmp_answer;
205
206   while (0 != idx)
207   {
208     r_idx = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
209                                       request->packet->num_answers);
210     idx--;
211     tmp_answer = request->packet->answers[idx];
212     memcpy (&request->packet->answers[idx], &request->packet->answers[r_idx],
213             sizeof (struct GNUNET_DNSPARSER_Record));
214     memcpy (&request->packet->answers[r_idx], &tmp_answer,
215             sizeof (struct GNUNET_DNSPARSER_Record));
216   }
217 }
218
219 /**
220  * Send the response for the given request and clean up.
221  *
222  * @param request context for the request.
223  */
224 static void
225 send_response (struct Request *request)
226 {
227   char *buf;
228   size_t size;
229   ssize_t sret;
230
231   shuffle_answers (request);
232   if (GNUNET_SYSERR ==
233       GNUNET_DNSPARSER_pack (request->packet,
234                              UINT16_MAX /* is this not too much? */,
235                              &buf,
236                              &size))
237   {
238     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
239                 _ ("Failed to pack DNS response into UDP packet!\n"));
240   }
241   else
242   {
243     sret = GNUNET_NETWORK_socket_sendto (request->lsock,
244                                          buf,
245                                          size,
246                                          request->addr,
247                                          request->addr_len);
248     if ((sret < 0) ||
249         (size != (size_t) sret))
250       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
251                            "sendto");
252     GNUNET_free (buf);
253   }
254   GNUNET_SCHEDULER_cancel (request->timeout_task);
255   GNUNET_DNSPARSER_free_packet (request->packet);
256   GNUNET_free (request->udp_msg);
257   GNUNET_free (request);
258 }
259
260
261 /**
262  * Task run on timeout.  Cleans up request.
263  *
264  * @param cls `struct Request *` of the request to clean up
265  */
266 static void
267 do_timeout (void *cls)
268 {
269   struct Request *request = cls;
270
271   if (NULL != request->packet)
272     GNUNET_DNSPARSER_free_packet (request->packet);
273   if (NULL != request->lookup)
274     GNUNET_GNS_lookup_with_tld_cancel (request->lookup);
275   if (NULL != request->dns_lookup)
276     GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
277   GNUNET_free (request->udp_msg);
278   GNUNET_free (request);
279 }
280
281
282 /**
283  * Iterator called on obtained result for a DNS lookup
284  *
285  * @param cls closure
286  * @param dns the DNS udp payload
287  * @param r size of the DNS payload
288  */
289 static void
290 dns_result_processor (void *cls,
291                       const struct GNUNET_TUN_DnsHeader *dns,
292                       size_t r)
293 {
294   struct Request *request = cls;
295
296   if (NULL == dns)
297   {
298     /* DNSSTUB gave up, so we trigger timeout early */
299     GNUNET_SCHEDULER_cancel (request->timeout_task);
300     do_timeout (request);
301     return;
302   }
303   if (request->original_request_id != dns->id)
304   {
305     /* for a another query, ignore */
306     return;
307   }
308   request->packet = GNUNET_DNSPARSER_parse ((char *) dns,
309                                             r);
310   GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
311   send_response (request);
312 }
313
314
315 /**
316  * Iterator called on obtained result for a GNS lookup.
317  *
318  * @param cls closure
319  * @param was_gns #GNUNET_NO if the TLD is not configured for GNS
320  * @param rd_count number of records in @a rd
321  * @param rd the records in reply
322  */
323 static void
324 result_processor (void *cls,
325                   int was_gns,
326                   uint32_t rd_count,
327                   const struct GNUNET_GNSRECORD_Data *rd)
328 {
329   struct Request *request = cls;
330   struct GNUNET_DNSPARSER_Packet *packet;
331   struct GNUNET_DNSPARSER_Record rec;
332
333   request->lookup = NULL;
334   if (GNUNET_NO == was_gns)
335   {
336     /* TLD not configured for GNS, fall back to DNS */
337     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338                 "Using DNS resolver IP `%s' to resolve `%s'\n",
339                 dns_ip,
340                 request->packet->queries[0].name);
341     request->original_request_id = request->packet->id;
342     GNUNET_DNSPARSER_free_packet (request->packet);
343     request->packet = NULL;
344     request->dns_lookup = GNUNET_DNSSTUB_resolve (dns_stub,
345                                                   request->udp_msg,
346                                                   request->udp_msg_size,
347                                                   &dns_result_processor,
348                                                   request);
349     return;
350   }
351   packet = request->packet;
352   packet->flags.query_or_response = 1;
353   packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
354   packet->flags.checking_disabled = 0;
355   packet->flags.authenticated_data = 1;
356   packet->flags.zero = 0;
357   packet->flags.recursion_available = 1;
358   packet->flags.message_truncated = 0;
359   packet->flags.authoritative_answer = 0;
360   // packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
361   for (uint32_t i = 0; i < rd_count; i++)
362   {
363     rec.expiration_time.abs_value_us = rd[i].expiration_time;
364     switch (rd[i].record_type)
365     {
366     case GNUNET_DNSPARSER_TYPE_A:
367       GNUNET_assert (sizeof(struct in_addr) == rd[i].data_size);
368       rec.name = GNUNET_strdup (packet->queries[0].name);
369       rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
370       rec.type = GNUNET_DNSPARSER_TYPE_A;
371       rec.data.raw.data = GNUNET_new (struct in_addr);
372       GNUNET_memcpy (rec.data.raw.data,
373                      rd[i].data,
374                      rd[i].data_size);
375       rec.data.raw.data_len = sizeof(struct in_addr);
376       GNUNET_array_append (packet->answers,
377                            packet->num_answers,
378                            rec);
379       break;
380
381     case GNUNET_DNSPARSER_TYPE_AAAA:
382       GNUNET_assert (sizeof(struct in6_addr) == rd[i].data_size);
383       rec.name = GNUNET_strdup (packet->queries[0].name);
384       rec.data.raw.data = GNUNET_new (struct in6_addr);
385       rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
386       rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
387       GNUNET_memcpy (rec.data.raw.data,
388                      rd[i].data,
389                      rd[i].data_size);
390       rec.data.raw.data_len = sizeof(struct in6_addr);
391       GNUNET_array_append (packet->answers,
392                            packet->num_answers,
393                            rec);
394       break;
395
396     case GNUNET_DNSPARSER_TYPE_CNAME:
397       rec.name = GNUNET_strdup (packet->queries[0].name);
398       rec.data.hostname = GNUNET_strdup (rd[i].data);
399       rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
400       rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
401       GNUNET_memcpy (rec.data.hostname,
402                      rd[i].data,
403                      rd[i].data_size);
404       GNUNET_array_append (packet->answers,
405                            packet->num_answers,
406                            rec);
407       break;
408
409     default:
410       /* skip */
411       break;
412     }
413   }
414   send_response (request);
415 }
416
417
418 /**
419  * Handle DNS request.
420  *
421  * @param lsock socket to use for sending the reply
422  * @param addr address to use for sending the reply
423  * @param addr_len number of bytes in @a addr
424  * @param udp_msg DNS request payload
425  * @param udp_msg_size number of bytes in @a udp_msg
426  */
427 static void
428 handle_request (struct GNUNET_NETWORK_Handle *lsock,
429                 const void *addr,
430                 size_t addr_len,
431                 const char *udp_msg,
432                 size_t udp_msg_size)
433 {
434   struct Request *request;
435   struct GNUNET_DNSPARSER_Packet *packet;
436
437   packet = GNUNET_DNSPARSER_parse (udp_msg,
438                                    udp_msg_size);
439   if (NULL == packet)
440   {
441     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
442                 _ ("Cannot parse DNS request from %s\n"),
443                 GNUNET_a2s (addr, addr_len));
444     return;
445   }
446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447               "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
448               packet->queries[0].name,
449               (unsigned int) packet->flags.query_or_response,
450               (int) packet->num_answers,
451               (int) packet->num_authority_records,
452               (int) packet->num_additional_records);
453   if ((0 != packet->flags.query_or_response) ||
454       (0 != packet->num_answers) ||
455       (0 != packet->num_authority_records))
456   {
457     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
458                 _ ("Received malformed DNS request from %s\n"),
459                 GNUNET_a2s (addr, addr_len));
460     GNUNET_DNSPARSER_free_packet (packet);
461     return;
462   }
463   if ((1 != packet->num_queries))
464   {
465     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
466                 _ ("Received unsupported DNS request from %s\n"),
467                 GNUNET_a2s (addr,
468                             addr_len));
469     GNUNET_DNSPARSER_free_packet (packet);
470     return;
471   }
472   request = GNUNET_malloc (sizeof(struct Request) + addr_len);
473   request->lsock = lsock;
474   request->packet = packet;
475   request->addr = &request[1];
476   request->addr_len = addr_len;
477   GNUNET_memcpy (&request[1],
478                  addr,
479                  addr_len);
480   request->udp_msg_size = udp_msg_size;
481   request->udp_msg = GNUNET_memdup (udp_msg,
482                                     udp_msg_size);
483   request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
484                                                         &do_timeout,
485                                                         request);
486   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487               "Calling GNS on `%s'\n",
488               packet->queries[0].name);
489   request->lookup = GNUNET_GNS_lookup_with_tld (gns,
490                                                 packet->queries[0].name,
491                                                 packet->queries[0].type,
492                                                 GNUNET_GNS_LO_DEFAULT,
493                                                 &result_processor,
494                                                 request);
495 }
496
497
498 /**
499  * Task to read IPv4 DNS packets.
500  *
501  * @param cls the 'listen_socket4'
502  */
503 static void
504 read_dns4 (void *cls)
505 {
506   struct sockaddr_in v4;
507   socklen_t addrlen;
508   ssize_t size;
509   const struct GNUNET_SCHEDULER_TaskContext *tc;
510
511   GNUNET_assert (listen_socket4 == cls);
512   t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
513                                       listen_socket4,
514                                       &read_dns4,
515                                       listen_socket4);
516   tc = GNUNET_SCHEDULER_get_task_context ();
517   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
518     return; /* shutdown? */
519   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
520   if (0 > size)
521   {
522     GNUNET_break (0);
523     return;   /* read error!? */
524   }
525   {
526     char buf[size + 1];
527     ssize_t sret;
528
529     addrlen = sizeof(v4);
530     sret = GNUNET_NETWORK_socket_recvfrom (listen_socket4,
531                                            buf,
532                                            size + 1,
533                                            (struct sockaddr *) &v4,
534                                            &addrlen);
535     if (0 > sret)
536     {
537       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
538                            "recvfrom");
539       return;
540     }
541     GNUNET_break (size == sret);
542     handle_request (listen_socket4,
543                     &v4,
544                     addrlen,
545                     buf,
546                     size);
547   }
548 }
549
550
551 /**
552  * Task to read IPv6 DNS packets.
553  *
554  * @param cls the 'listen_socket6'
555  */
556 static void
557 read_dns6 (void *cls)
558 {
559   struct sockaddr_in6 v6;
560   socklen_t addrlen;
561   ssize_t size;
562   const struct GNUNET_SCHEDULER_TaskContext *tc;
563
564   GNUNET_assert (listen_socket6 == cls);
565   t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
566                                       listen_socket6,
567                                       &read_dns6,
568                                       listen_socket6);
569   tc = GNUNET_SCHEDULER_get_task_context ();
570   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
571     return; /* shutdown? */
572   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
573   if (0 > size)
574   {
575     GNUNET_break (0);
576     return;   /* read error!? */
577   }
578   {
579     char buf[size];
580     ssize_t sret;
581
582     addrlen = sizeof(v6);
583     sret = GNUNET_NETWORK_socket_recvfrom (listen_socket6,
584                                            buf,
585                                            size,
586                                            (struct sockaddr *) &v6,
587                                            &addrlen);
588     if (0 > sret)
589     {
590       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
591                            "recvfrom");
592       return;
593     }
594     GNUNET_break (size == sret);
595     handle_request (listen_socket6,
596                     &v6,
597                     addrlen,
598                     buf,
599                     size);
600   }
601 }
602
603
604 /**
605  * Main function that will be run.
606  *
607  * @param cls closure
608  * @param args remaining command-line arguments
609  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
610  * @param c configuration
611  */
612 static void
613 run (void *cls,
614      char *const *args,
615      const char *cfgfile,
616      const struct GNUNET_CONFIGURATION_Handle *c)
617 {
618   char *addr_str;
619
620   (void) cls;
621   (void) args;
622   (void) cfgfile;
623   cfg = c;
624   if (NULL == dns_ip)
625   {
626     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
627                 _ ("No DNS server specified!\n"));
628     return;
629   }
630   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
631                                  NULL);
632   if (NULL == (gns = GNUNET_GNS_connect (cfg)))
633     return;
634   GNUNET_assert (NULL != (dns_stub = GNUNET_DNSSTUB_start (128)));
635   if (GNUNET_OK !=
636       GNUNET_DNSSTUB_add_dns_ip (dns_stub,
637                                  dns_ip))
638   {
639     GNUNET_DNSSTUB_stop (dns_stub);
640     GNUNET_GNS_disconnect (gns);
641     gns = NULL;
642     return;
643   }
644
645   /* Get address to bind to */
646   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
647                                                           "BIND_TO",
648                                                           &addr_str))
649   {
650     // No address specified
651     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
652                 "Don't know what to bind to...\n");
653     GNUNET_free (addr_str);
654     GNUNET_SCHEDULER_shutdown ();
655     return;
656   }
657   if (1 != inet_pton (AF_INET, addr_str, &address))
658   {
659     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
660                 "Unable to parse address %s\n",
661                 addr_str);
662     GNUNET_free (addr_str);
663     GNUNET_SCHEDULER_shutdown ();
664     return;
665   }
666   GNUNET_free (addr_str);
667   /* Get address to bind to */
668   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
669                                                           "BIND_TO6",
670                                                           &addr_str))
671   {
672     // No address specified
673     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674                 "Don't know what to bind6 to...\n");
675     GNUNET_free (addr_str);
676     GNUNET_SCHEDULER_shutdown ();
677     return;
678   }
679   if (1 != inet_pton (AF_INET6, addr_str, &address6))
680   {
681     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
682                 "Unable to parse IPv6 address %s\n",
683                 addr_str);
684     GNUNET_free (addr_str);
685     GNUNET_SCHEDULER_shutdown ();
686     return;
687   }
688   GNUNET_free (addr_str);
689
690   listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
691                                                  SOCK_DGRAM,
692                                                  IPPROTO_UDP);
693   if (NULL != listen_socket4)
694   {
695     struct sockaddr_in v4;
696
697     memset (&v4, 0, sizeof(v4));
698     v4.sin_family = AF_INET;
699     v4.sin_addr.s_addr = address;
700 #if HAVE_SOCKADDR_IN_SIN_LEN
701     v4.sin_len = sizeof(v4);
702 #endif
703     v4.sin_port = htons (listen_port);
704     if (GNUNET_OK !=
705         GNUNET_NETWORK_socket_bind (listen_socket4,
706                                     (struct sockaddr *) &v4,
707                                     sizeof(v4)))
708     {
709       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
710       GNUNET_NETWORK_socket_close (listen_socket4);
711       listen_socket4 = NULL;
712     }
713   }
714   listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
715                                                  SOCK_DGRAM,
716                                                  IPPROTO_UDP);
717   if (NULL != listen_socket6)
718   {
719     struct sockaddr_in6 v6;
720
721     memset (&v6, 0, sizeof(v6));
722     v6.sin6_family = AF_INET6;
723     v6.sin6_addr = address6;
724 #if HAVE_SOCKADDR_IN_SIN_LEN
725     v6.sin6_len = sizeof(v6);
726 #endif
727     v6.sin6_port = htons (listen_port);
728     if (GNUNET_OK !=
729         GNUNET_NETWORK_socket_bind (listen_socket6,
730                                     (struct sockaddr *) &v6,
731                                     sizeof(v6)))
732     {
733       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
734       GNUNET_NETWORK_socket_close (listen_socket6);
735       listen_socket6 = NULL;
736     }
737   }
738   if ((NULL == listen_socket4) &&
739       (NULL == listen_socket6))
740   {
741     GNUNET_GNS_disconnect (gns);
742     gns = NULL;
743     GNUNET_DNSSTUB_stop (dns_stub);
744     dns_stub = NULL;
745     return;
746   }
747   if (NULL != listen_socket4)
748     t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
749                                         listen_socket4,
750                                         &read_dns4,
751                                         listen_socket4);
752   if (NULL != listen_socket6)
753     t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
754                                         listen_socket6,
755                                         &read_dns6,
756                                         listen_socket6);
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   struct GNUNET_GETOPT_CommandLineOption options[] = {
772     GNUNET_GETOPT_option_string ('d',
773                                  "dns",
774                                  "IP",
775                                  gettext_noop (
776                                    "IP of recursive DNS resolver to use (required)"),
777                                  &dns_ip),
778     GNUNET_GETOPT_option_uint ('p',
779                                "port",
780                                "UDPPORT",
781                                gettext_noop (
782                                  "UDP port to listen on for inbound DNS requests; default: 2853"),
783                                &listen_port),
784     GNUNET_GETOPT_OPTION_END
785   };
786   int ret;
787
788   if (GNUNET_OK !=
789       GNUNET_STRINGS_get_utf8_args (argc, argv,
790                                     &argc, &argv))
791     return 2;
792   GNUNET_log_setup ("gnunet-dns2gns",
793                     "WARNING",
794                     NULL);
795   ret =
796     (GNUNET_OK ==
797      GNUNET_PROGRAM_run (argc, argv,
798                          "gnunet-dns2gns",
799                          _ ("GNUnet DNS-to-GNS proxy (a DNS server)"),
800                          options,
801                          &run, NULL)) ? 0 : 1;
802   GNUNET_free_nz ((void *) argv);
803   return ret;
804 }
805
806
807 /* end of gnunet-dns2gns.c */