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