3d16cd773b49406d5e2f12702c0e3b47e9d14160
[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_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
91 /**
92  * Handle to GNS resolver.
93  */
94 struct GNUNET_GNS_Handle *gns;
95
96 /**
97  * Stub resolver
98  */
99 struct GNUNET_DNSSTUB_Context *dns_stub;
100
101 /**
102  * Listen socket for IPv4.
103  */
104 static struct GNUNET_NETWORK_Handle *listen_socket4;
105
106 /**
107  * Listen socket for IPv6.
108  */
109 static struct GNUNET_NETWORK_Handle *listen_socket6;
110
111 /**
112  * Task for IPv4 socket.
113  */
114 static struct GNUNET_SCHEDULER_Task *t4;
115
116 /**
117  * Task for IPv6 socket.
118  */
119 static struct GNUNET_SCHEDULER_Task *t6;
120
121 /**
122  * IP of DNS server
123  */
124 static char *dns_ip;
125
126 /**
127  * UDP Port we listen on for inbound DNS requests.
128  */
129 static unsigned int listen_port = 53;
130
131 /**
132  * Configuration to use.
133  */
134 static const struct GNUNET_CONFIGURATION_Handle *cfg;
135
136
137 /**
138  * Task run on shutdown.  Cleans up everything.
139  *
140  * @param cls unused
141  */
142 static void
143 do_shutdown (void *cls)
144 {
145   (void) cls;
146   if (NULL != t4)
147   {
148     GNUNET_SCHEDULER_cancel (t4);
149     t4 = NULL;
150   }
151   if (NULL != t6)
152   {
153     GNUNET_SCHEDULER_cancel (t6);
154     t6 = NULL;
155   }
156   if (NULL != listen_socket4)
157   {
158     GNUNET_NETWORK_socket_close (listen_socket4);
159     listen_socket4 = NULL;
160   }
161   if (NULL != listen_socket6)
162   {
163     GNUNET_NETWORK_socket_close (listen_socket6);
164     listen_socket6 = NULL;
165   }
166   if (NULL != gns)
167   {
168     GNUNET_GNS_disconnect (gns);
169     gns = NULL;
170   }
171   if (NULL != dns_stub)
172   {
173     GNUNET_DNSSTUB_stop (dns_stub);
174     dns_stub = NULL;
175   }
176 }
177
178
179 /**
180  * Send the response for the given request and clean up.
181  *
182  * @param request context for the request.
183  */
184 static void
185 send_response (struct Request *request)
186 {
187   char *buf;
188   size_t size;
189   ssize_t sret;
190
191   if (GNUNET_SYSERR ==
192       GNUNET_DNSPARSER_pack (request->packet,
193                              UINT16_MAX /* is this not too much? */,
194                              &buf,
195                              &size))
196     {
197       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
198                   _("Failed to pack DNS response into UDP packet!\n"));
199     }
200   else
201     {
202       sret = GNUNET_NETWORK_socket_sendto (request->lsock,
203                                            buf,
204                                            size,
205                                            request->addr,
206                                            request->addr_len);
207       if ( (sret < 0) ||
208            (size != (size_t) sret) )
209         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
210                              "sendto");
211       GNUNET_free (buf);
212     }
213   GNUNET_SCHEDULER_cancel (request->timeout_task);
214   GNUNET_DNSPARSER_free_packet (request->packet);
215   GNUNET_free (request->udp_msg);
216   GNUNET_free (request);
217 }
218
219
220 /**
221  * Task run on timeout.  Cleans up request.
222  *
223  * @param cls `struct Request *` of the request to clean up
224  */
225 static void
226 do_timeout (void *cls)
227 {
228   struct Request *request = cls;
229
230   if (NULL != request->packet)
231     GNUNET_DNSPARSER_free_packet (request->packet);
232   if (NULL != request->lookup)
233     GNUNET_GNS_lookup_with_tld_cancel (request->lookup);
234   if (NULL != request->dns_lookup)
235     GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
236   GNUNET_free (request->udp_msg);
237   GNUNET_free (request);
238 }
239
240
241 /**
242  * Iterator called on obtained result for a DNS lookup
243  *
244  * @param cls closure
245  * @param rs the request socket
246  * @param dns the DNS udp payload
247  * @param r size of the DNS payload
248  */
249 static void
250 dns_result_processor (void *cls,
251                       struct GNUNET_DNSSTUB_RequestSocket *rs,
252                       const struct GNUNET_TUN_DnsHeader *dns,
253                       size_t r)
254 {
255   struct Request *request = cls;
256
257   (void) rs;
258   request->packet = GNUNET_DNSPARSER_parse ((char*)dns,
259                                             r);
260   send_response (request);
261 }
262
263
264 /**
265  * Iterator called on obtained result for a GNS lookup.
266  *
267  * @param cls closure
268  * @param was_gns #GNUNET_NO if the TLD is not configured for GNS
269  * @param rd_count number of records in @a rd
270  * @param rd the records in reply
271  */
272 static void
273 result_processor (void *cls,
274                   int was_gns,
275                   uint32_t rd_count,
276                   const struct GNUNET_GNSRECORD_Data *rd)
277 {
278   struct Request *request = cls;
279   struct GNUNET_DNSPARSER_Packet *packet;
280   uint32_t i;
281   struct GNUNET_DNSPARSER_Record rec;
282
283   request->lookup = NULL;
284   if (GNUNET_NO == was_gns)
285   {
286     /* TLD not configured for GNS, fall back to DNS */
287     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288                 "Using DNS resolver IP `%s' to resolve `%s'\n",
289                 dns_ip,
290                 request->packet->queries[0].name);
291     GNUNET_DNSPARSER_free_packet (request->packet);
292     request->packet = NULL;
293     request->dns_lookup = GNUNET_DNSSTUB_resolve2 (dns_stub,
294                                                    request->udp_msg,
295                                                    request->udp_msg_size,
296                                                    &dns_result_processor,
297                                                    request);
298     return;
299   }  
300   packet = request->packet;
301   packet->flags.query_or_response = 1;
302   packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
303   packet->flags.checking_disabled = 0;
304   packet->flags.authenticated_data = 1;
305   packet->flags.zero = 0;
306   packet->flags.recursion_available = 1;
307   packet->flags.message_truncated = 0;
308   packet->flags.authoritative_answer = 0;
309   //packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
310   for (i=0;i<rd_count;i++)
311     {
312       // FIXME: do we need to hanlde #GNUNET_GNSRECORD_RF_SHADOW_RECORD
313       // here? Or should we do this in libgnunetgns?
314       rec.expiration_time.abs_value_us = rd[i].expiration_time;
315       switch (rd[i].record_type)
316         {
317         case GNUNET_DNSPARSER_TYPE_A:
318           GNUNET_assert (sizeof (struct in_addr) == rd[i].data_size);
319           rec.name = GNUNET_strdup (packet->queries[0].name);
320           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
321           rec.type = GNUNET_DNSPARSER_TYPE_A;
322           rec.data.raw.data = GNUNET_new (struct in_addr);
323           GNUNET_memcpy (rec.data.raw.data,
324                   rd[i].data,
325                   rd[i].data_size);
326           rec.data.raw.data_len = sizeof (struct in_addr);
327           GNUNET_array_append (packet->answers,
328                                packet->num_answers,
329                                rec);
330           break;
331         case GNUNET_DNSPARSER_TYPE_AAAA:
332           GNUNET_assert (sizeof (struct in6_addr) == rd[i].data_size);
333           rec.name = GNUNET_strdup (packet->queries[0].name);
334           rec.data.raw.data = GNUNET_new (struct in6_addr);
335           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
336           rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
337           GNUNET_memcpy (rec.data.raw.data,
338                   rd[i].data,
339                   rd[i].data_size);
340           rec.data.raw.data_len = sizeof (struct in6_addr);
341           GNUNET_array_append (packet->answers,
342                                packet->num_answers,
343                                rec);
344           break;
345         case GNUNET_DNSPARSER_TYPE_CNAME:
346           rec.name = GNUNET_strdup (packet->queries[0].name);
347           rec.data.hostname = GNUNET_strdup (rd[i].data);
348           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
349           rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
350           GNUNET_memcpy (rec.data.hostname,
351                   rd[i].data,
352                   rd[i].data_size);
353           GNUNET_array_append (packet->answers,
354                                packet->num_answers,
355                                rec);
356           break;
357         default:
358           /* skip */
359           break;
360         }
361     }
362   send_response (request);
363 }
364
365
366 /**
367  * Handle DNS request.
368  *
369  * @param lsock socket to use for sending the reply
370  * @param addr address to use for sending the reply
371  * @param addr_len number of bytes in @a addr
372  * @param udp_msg DNS request payload
373  * @param udp_msg_size number of bytes in @a udp_msg
374  */
375 static void
376 handle_request (struct GNUNET_NETWORK_Handle *lsock,
377                 const void *addr,
378                 size_t addr_len,
379                 const char *udp_msg,
380                 size_t udp_msg_size)
381 {
382   struct Request *request;
383   struct GNUNET_DNSPARSER_Packet *packet;
384
385   packet = GNUNET_DNSPARSER_parse (udp_msg,
386                                    udp_msg_size);
387   if (NULL == packet)
388   {
389     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
390                 _("Cannot parse DNS request from %s\n"),
391                 GNUNET_a2s (addr, addr_len));
392     return;
393   }
394   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395               "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
396               packet->queries[0].name,
397               (unsigned int) packet->flags.query_or_response,
398               (int) packet->num_answers,
399               (int) packet->num_authority_records,
400               (int) packet->num_additional_records);
401   if ( (0 != packet->flags.query_or_response) ||
402        (0 != packet->num_answers) ||
403        (0 != packet->num_authority_records))
404   {
405     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
406                 _("Received malformed DNS request from %s\n"),
407                 GNUNET_a2s (addr, addr_len));
408     GNUNET_DNSPARSER_free_packet (packet);
409     return;
410   }
411   if ( (1 != packet->num_queries) )
412   {
413     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
414                 _("Received unsupported DNS request from %s\n"),
415                 GNUNET_a2s (addr,
416                             addr_len));
417     GNUNET_DNSPARSER_free_packet (packet);
418     return;
419   }
420   request = GNUNET_malloc (sizeof (struct Request) + addr_len);
421   request->lsock = lsock;
422   request->packet = packet;
423   request->addr = &request[1];
424   request->addr_len = addr_len;
425   GNUNET_memcpy (&request[1],
426                  addr,
427                  addr_len);
428   request->udp_msg_size = udp_msg_size;
429   request->udp_msg = GNUNET_memdup (udp_msg,
430                                     udp_msg_size);
431   request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
432                                                         &do_timeout,
433                                                         request);
434   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
435               "Calling GNS on `%s'\n",
436               packet->queries[0].name);
437   request->lookup = GNUNET_GNS_lookup_with_tld (gns,
438                                                 packet->queries[0].name,
439                                                 packet->queries[0].type,
440                                                 GNUNET_NO,
441                                                 &result_processor,
442                                                 request);
443 }
444
445
446 /**
447  * Task to read IPv4 DNS packets.
448  *
449  * @param cls the 'listen_socket4'
450  */
451 static void
452 read_dns4 (void *cls)
453 {
454   struct sockaddr_in v4;
455   socklen_t addrlen;
456   ssize_t size;
457   const struct GNUNET_SCHEDULER_TaskContext *tc;
458
459   GNUNET_assert (listen_socket4 == cls);
460   t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
461                                       listen_socket4,
462                                       &read_dns4,
463                                       listen_socket4);
464   tc = GNUNET_SCHEDULER_get_task_context ();
465   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
466     return; /* shutdown? */
467   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
468   if (0 > size)
469     {
470       GNUNET_break (0);
471       return; /* read error!? */
472     }
473   {
474     char buf[size + 1];
475     ssize_t sret;
476
477     addrlen = sizeof (v4);
478     sret = GNUNET_NETWORK_socket_recvfrom (listen_socket4,
479                                            buf,
480                                            size + 1,
481                                            (struct sockaddr *) &v4,
482                                            &addrlen);
483     if (0 > sret)
484     {
485       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
486                            "recvfrom");
487       return;
488     }
489     GNUNET_break (size == sret);
490     handle_request (listen_socket4,
491                     &v4,
492                     addrlen,
493                     buf,
494                     size);
495   }
496 }
497
498
499 /**
500  * Task to read IPv6 DNS packets.
501  *
502  * @param cls the 'listen_socket6'
503  */
504 static void
505 read_dns6 (void *cls)
506 {
507   struct sockaddr_in6 v6;
508   socklen_t addrlen;
509   ssize_t size;
510   const struct GNUNET_SCHEDULER_TaskContext *tc;
511
512   GNUNET_assert (listen_socket6 == cls);
513   t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
514                                       listen_socket6,
515                                       &read_dns6,
516                                       listen_socket6);
517   tc = GNUNET_SCHEDULER_get_task_context ();
518   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
519     return; /* shutdown? */
520   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
521   if (0 > size)
522     {
523       GNUNET_break (0);
524       return; /* read error!? */
525     }
526   {
527     char buf[size];
528     ssize_t sret;
529
530     addrlen = sizeof (v6);
531     sret = GNUNET_NETWORK_socket_recvfrom (listen_socket6,
532                                            buf,
533                                            size,
534                                            (struct sockaddr *) &v6,
535                                            &addrlen);
536     if (0 > sret)
537     {
538       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
539                            "recvfrom");
540       return;
541     }
542     GNUNET_break (size == sret);
543     handle_request (listen_socket6,
544                     &v6,
545                     addrlen,
546                     buf,
547                     size);
548   }
549 }
550
551
552 /**
553  * Main function that will be run.
554  *
555  * @param cls closure
556  * @param args remaining command-line arguments
557  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
558  * @param c configuration
559  */
560 static void
561 run (void *cls,
562      char *const *args,
563      const char *cfgfile,
564      const struct GNUNET_CONFIGURATION_Handle *c)
565 {
566   (void) cls;
567   (void) args;
568   (void) cfgfile;
569   cfg = c;
570   if (NULL == dns_ip)
571   {
572     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573                 _("No DNS server specified!\n"));
574     return;
575   }
576   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
577                                  NULL);
578   if (NULL == (gns = GNUNET_GNS_connect (cfg)))
579     return;
580   if (NULL == (dns_stub = GNUNET_DNSSTUB_start (dns_ip)))
581   {
582     GNUNET_GNS_disconnect (gns);
583     gns = NULL;
584     return;
585   }
586   listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
587                                                  SOCK_DGRAM,
588                                                  IPPROTO_UDP);
589   if (NULL != listen_socket4)
590   {
591     struct sockaddr_in v4;
592
593     memset (&v4, 0, sizeof (v4));
594     v4.sin_family = AF_INET;
595 #if HAVE_SOCKADDR_IN_SIN_LEN
596     v4.sin_len = sizeof (v4);
597 #endif
598     v4.sin_port = htons (listen_port);
599     if (GNUNET_OK !=
600         GNUNET_NETWORK_socket_bind (listen_socket4,
601                                     (struct sockaddr *) &v4,
602                                     sizeof (v4)))
603     {
604       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
605       GNUNET_NETWORK_socket_close (listen_socket4);
606       listen_socket4 = NULL;
607     }
608   }
609   listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
610                                                 SOCK_DGRAM,
611                                                 IPPROTO_UDP);
612   if (NULL != listen_socket6)
613   {
614     struct sockaddr_in6 v6;
615
616     memset (&v6, 0, sizeof (v6));
617     v6.sin6_family = AF_INET6;
618 #if HAVE_SOCKADDR_IN_SIN_LEN
619     v6.sin6_len = sizeof (v6);
620 #endif
621     v6.sin6_port = htons (listen_port);
622     if (GNUNET_OK !=
623         GNUNET_NETWORK_socket_bind (listen_socket6,
624                                     (struct sockaddr *) &v6,
625                                     sizeof (v6)))
626     {
627       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
628       GNUNET_NETWORK_socket_close (listen_socket6);
629       listen_socket6 = NULL;
630     }
631   }
632   if ( (NULL == listen_socket4) &&
633        (NULL == listen_socket6) )
634   {
635     GNUNET_GNS_disconnect (gns);
636     gns = NULL;
637     GNUNET_DNSSTUB_stop (dns_stub);
638     dns_stub = NULL;
639     return;
640   }
641   if (NULL != listen_socket4)
642     t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
643                                         listen_socket4,
644                                         &read_dns4,
645                                         listen_socket4);
646   if (NULL != listen_socket6)
647     t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
648                                         listen_socket6,
649                                         &read_dns6,
650                                         listen_socket6);
651 }
652
653
654 /**
655  * The main function for the dns2gns daemon.
656  *
657  * @param argc number of arguments from the command line
658  * @param argv command line arguments
659  * @return 0 ok, 1 on error
660  */
661 int
662 main (int argc,
663       char *const *argv)
664 {
665   struct GNUNET_GETOPT_CommandLineOption options[] = {
666     GNUNET_GETOPT_option_string ('d',
667                                  "dns",
668                                  "IP",
669                                  gettext_noop ("IP of recursive DNS resolver to use (required)"),
670                                  &dns_ip),
671     GNUNET_GETOPT_option_uint ('p',
672                                "port",
673                                "UDPPORT",
674                                gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"),
675                                &listen_port),
676     GNUNET_GETOPT_OPTION_END
677   };
678   int ret;
679
680   if (GNUNET_OK !=
681       GNUNET_STRINGS_get_utf8_args (argc, argv,
682                                     &argc, &argv))
683     return 2;
684   GNUNET_log_setup ("gnunet-dns2gns",
685                     "WARNING",
686                     NULL);
687   ret =
688       (GNUNET_OK ==
689        GNUNET_PROGRAM_run (argc, argv,
690                            "gnunet-dns2gns",
691                            _("GNUnet DNS-to-GNS proxy (a DNS server)"),
692                            options,
693                            &run, NULL)) ? 0 : 1;
694   GNUNET_free ((void*) argv);
695   return ret;
696 }
697
698 /* end of gnunet-dns2gns.c */