use idn2.h or idna.h depending on HAVE_LIBIDN/HAVE_LIBIDN
[oweals/gnunet.git] / src / util / resolver_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2018 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 /**
22  * @file util/resolver_api.c
23  * @brief resolver for writing a tool
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_resolver_service.h"
30 #include "resolver.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
33
34 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-resolver-api", syscall)
35
36 /**
37  * Maximum supported length for a hostname
38  */
39 #define MAX_HOSTNAME 1024
40
41
42 /**
43  * Possible hostnames for "loopback".
44  */
45 static const char *loopback[] = {
46   "localhost",
47   "ip6-localnet",
48   NULL
49 };
50
51
52 /**
53  * Configuration.
54  */
55 static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg;
56
57 /**
58  * Our connection to the resolver service, created on-demand, but then
59  * persists until error or shutdown.
60  */
61 static struct GNUNET_MQ_Handle *mq;
62
63 /**
64  * Head of DLL of requests.
65  */
66 static struct GNUNET_RESOLVER_RequestHandle *req_head;
67
68 /**
69  * Tail of DLL of requests.
70  */
71 static struct GNUNET_RESOLVER_RequestHandle *req_tail;
72
73 /**
74  * ID of the last request we sent to the service
75  */
76 static uint32_t last_request_id;
77
78 /**
79  * How long should we wait to reconnect?
80  */
81 static struct GNUNET_TIME_Relative backoff;
82
83 /**
84  * Task for reconnecting.
85  */
86 static struct GNUNET_SCHEDULER_Task *r_task;
87
88 /**
89  * Task ID of shutdown task; only present while we have a
90  * connection to the resolver service.
91  */
92 static struct GNUNET_SCHEDULER_Task *s_task;
93
94
95 /**
96  * Handle to a request given to the resolver.  Can be used to cancel
97  * the request prior to the timeout or successful execution.  Also
98  * used to track our internal state for the request.
99  */
100 struct GNUNET_RESOLVER_RequestHandle
101 {
102
103   /**
104    * Next entry in DLL of requests.
105    */
106   struct GNUNET_RESOLVER_RequestHandle *next;
107
108   /**
109    * Previous entry in DLL of requests.
110    */
111   struct GNUNET_RESOLVER_RequestHandle *prev;
112
113   /**
114    * Callback if this is an name resolution request,
115    * otherwise NULL.
116    */
117   GNUNET_RESOLVER_AddressCallback addr_callback;
118
119   /**
120    * Callback if this is a reverse lookup request,
121    * otherwise NULL.
122    */
123   GNUNET_RESOLVER_HostnameCallback name_callback;
124
125   /**
126    * Closure for the callbacks.
127    */
128   void *cls;
129
130   /**
131    * When should this request time out?
132    */
133   struct GNUNET_TIME_Absolute timeout;
134
135   /**
136    * Task handle for making reply callbacks in numeric lookups
137    * asynchronous, and for timeout handling.
138    */
139   struct GNUNET_SCHEDULER_Task *task;
140
141   /**
142    * Desired address family.
143    */
144   int af;
145
146   /**
147    * Identifies the request. The response will contain this id.
148    */
149   uint32_t id;
150
151   /**
152    * Has this request been transmitted to the service?
153    * #GNUNET_YES if transmitted
154    * #GNUNET_YES if not transmitted
155    * #GNUNET_SYSERR when request was canceled
156    */
157   int was_transmitted;
158
159   /**
160    * Did we add this request to the queue?
161    */
162   int was_queued;
163
164   /**
165    * Desired direction (IP to name or name to IP)
166    */
167   int direction;
168
169   /**
170    * #GNUNET_YES if a response was received
171    */
172   int received_response;
173
174   /**
175    * Length of the data that follows this struct.
176    */
177   size_t data_len;
178 };
179
180
181 /**
182  * Check that the resolver service runs on localhost
183  * (or equivalent).
184  *
185  * @return #GNUNET_OK if the resolver is properly configured,
186  *         #GNUNET_SYSERR otherwise.
187  */
188 static int
189 check_config ()
190 {
191   char *hostname;
192   struct sockaddr_in v4;
193   struct sockaddr_in6 v6;
194
195   if (GNUNET_OK ==
196       GNUNET_CONFIGURATION_have_value (resolver_cfg,
197                                        "resolver",
198                                        "UNIXPATH"))
199     return GNUNET_OK;
200   memset (&v4, 0, sizeof (v4));
201   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
202   v4.sin_family = AF_INET;
203 #if HAVE_SOCKADDR_IN_SIN_LEN
204   v4.sin_len = sizeof (v4);
205 #endif
206   memset (&v6, 0, sizeof (v6));
207   v6.sin6_family = AF_INET6;
208 #if HAVE_SOCKADDR_IN_SIN_LEN
209   v6.sin6_len = sizeof (v6);
210 #endif
211   if (GNUNET_OK !=
212       GNUNET_CONFIGURATION_get_value_string (resolver_cfg,
213                                              "resolver",
214                                              "HOSTNAME",
215                                              &hostname))
216   {
217     LOG (GNUNET_ERROR_TYPE_INFO,
218          _("Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"),
219          "HOSTNAME",
220          "resolver");
221     return GNUNET_SYSERR;
222   }
223   if ( (1 == inet_pton (AF_INET, hostname, &v4)) ||
224        (1 == inet_pton (AF_INET6, hostname, &v6)) )
225   {
226     GNUNET_free (hostname);
227     return GNUNET_OK;
228   }
229   for (unsigned int i = 0;
230        NULL != loopback[i];
231        i++)
232     if (0 == strcasecmp (loopback[i],
233                          hostname))
234     {
235       GNUNET_free (hostname);
236       return GNUNET_OK;
237     }
238   LOG (GNUNET_ERROR_TYPE_INFO,
239        _("Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
240        "localhost",
241        "HOSTNAME",
242        "resolver");
243   GNUNET_free (hostname);
244   return GNUNET_SYSERR;
245 }
246
247
248 /**
249  * Create the connection to the resolver service.
250  *
251  * @param cfg configuration to use
252  */
253 void
254 GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
255 {
256   GNUNET_assert (NULL != cfg);
257   backoff = GNUNET_TIME_UNIT_MILLISECONDS;
258   resolver_cfg = cfg;
259 }
260
261
262 /**
263  * Destroy the connection to the resolver service.
264  */
265 void
266 GNUNET_RESOLVER_disconnect ()
267 {
268   struct GNUNET_RESOLVER_RequestHandle *rh;
269
270   while (NULL != (rh = req_head))
271   {
272     GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted);
273     GNUNET_CONTAINER_DLL_remove (req_head,
274                                  req_tail,
275                                  rh);
276     GNUNET_free (rh);
277   }
278   if (NULL != mq)
279   {
280     LOG (GNUNET_ERROR_TYPE_DEBUG,
281          "Disconnecting from DNS service\n");
282     GNUNET_MQ_destroy (mq);
283     mq = NULL;
284   }
285   if (NULL != r_task)
286   {
287     GNUNET_SCHEDULER_cancel (r_task);
288     r_task = NULL;
289   }
290   if (NULL != s_task)
291   {
292     GNUNET_SCHEDULER_cancel (s_task);
293     s_task = NULL;
294   }
295 }
296
297
298 /**
299  * Task executed on system shutdown.
300  */
301 static void
302 shutdown_task (void *cls)
303 {
304   (void) cls;
305   s_task = NULL;
306   GNUNET_RESOLVER_disconnect ();
307   backoff = GNUNET_TIME_UNIT_MILLISECONDS;
308 }
309
310
311 /**
312  * Consider disconnecting if we have no further requests pending.
313  */
314 static void
315 check_disconnect ()
316 {
317   for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
318        NULL != rh;
319        rh = rh->next)
320     if (GNUNET_SYSERR != rh->was_transmitted)
321       return;
322   if (NULL != r_task)
323   {
324     GNUNET_SCHEDULER_cancel (r_task);
325     r_task = NULL;
326   }
327   if (NULL != s_task)
328     return;
329   s_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
330                                          &shutdown_task,
331                                          NULL);
332 }
333
334
335 /**
336  * Convert IP address to string without DNS resolution.
337  *
338  * @param af address family
339  * @param ip the address
340  * @param ip_len number of bytes in @a ip
341  * @return address as a string, NULL on error
342  */
343 static char *
344 no_resolve (int af,
345             const void *ip,
346             socklen_t ip_len)
347 {
348   char buf[INET6_ADDRSTRLEN];
349
350   switch (af)
351   {
352   case AF_INET:
353     if (ip_len != sizeof (struct in_addr))
354       return NULL;
355     if (NULL ==
356         inet_ntop (AF_INET,
357                    ip,
358                    buf,
359                    sizeof (buf)))
360     {
361       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
362                     "inet_ntop");
363       return NULL;
364     }
365     break;
366   case AF_INET6:
367     if (ip_len != sizeof (struct in6_addr))
368       return NULL;
369     if (NULL ==
370         inet_ntop (AF_INET6,
371                    ip,
372                    buf,
373                    sizeof (buf)))
374     {
375       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
376                     "inet_ntop");
377       return NULL;
378     }
379     break;
380   default:
381     GNUNET_break (0);
382     return NULL;
383   }
384   return GNUNET_strdup (buf);
385 }
386
387
388 /**
389  * Adjust exponential back-off and reconnect to the service.
390  */
391 static void
392 reconnect (void);
393
394
395 /**
396  * Generic error handler, called with the appropriate error code and
397  * the same closure specified at the creation of the message queue.
398  * Not every message queue implementation supports an error handler.
399  *
400  * @param cls NULL
401  * @param error error code
402  */
403 static void
404 mq_error_handler (void *cls,
405                   enum GNUNET_MQ_Error error)
406 {
407   (void) cls;
408   GNUNET_MQ_destroy (mq);
409   mq = NULL;
410   LOG (GNUNET_ERROR_TYPE_DEBUG,
411        "MQ error %d, reconnecting\n",
412        error);
413   reconnect ();
414 }
415
416
417 /**
418  * Process pending requests to the resolver.
419  */
420 static void
421 process_requests ()
422 {
423   struct GNUNET_RESOLVER_GetMessage *msg;
424   struct GNUNET_MQ_Envelope *env;
425   struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
426
427   if (NULL == mq)
428   {
429     reconnect ();
430     return;
431   }
432   if (NULL == rh)
433   {
434     /* nothing to do, release socket really soon if there is nothing
435      * else happening... */
436     if (NULL == s_task)
437       s_task =
438         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
439                                       &shutdown_task,
440                                       NULL);
441     return;
442   }
443   if (GNUNET_NO != rh->was_transmitted)
444     return;                     /* waiting for reply */
445   env = GNUNET_MQ_msg_extra (msg,
446                              rh->data_len,
447                              GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
448   msg->direction = htonl (rh->direction);
449   msg->af = htonl (rh->af);
450   msg->client_id = rh->id;
451   GNUNET_memcpy (&msg[1],
452                  &rh[1],
453                  rh->data_len);
454   LOG (GNUNET_ERROR_TYPE_DEBUG,
455        "Transmitting DNS resolution request (ID %u) to DNS service\n",
456        rh->id);
457   GNUNET_MQ_send (mq,
458                   env);
459   rh->was_transmitted = GNUNET_YES;
460 }
461
462
463 /**
464  * Check validity of response with a hostname for a DNS lookup.
465  *
466  * @param cls NULL
467  * @param msg message with the hostname
468  */
469 static int
470 check_response (void *cls,
471                 const struct GNUNET_RESOLVER_ResponseMessage *msg)
472 {
473   (void) cls;
474   (void) msg;
475
476   /* implemented in #handle_response() for now */
477   return GNUNET_OK;
478 }
479
480
481 /**
482  * Check validity of response with a hostname for a DNS lookup.
483  * NOTE: right now rather messy, might want to use different
484  * message types for different response formats in the future.
485  *
486  * @param cls NULL
487  * @param msg message with the response
488  */
489 static void
490 handle_response (void *cls,
491                  const struct GNUNET_RESOLVER_ResponseMessage *msg)
492 {
493   struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
494   uint16_t size;
495   char *nret;
496   uint32_t client_request_id = msg->client_id;
497
498   for (; rh != NULL; rh = rh->next)
499   {
500     if (rh->id == client_request_id)
501       break;
502   }
503
504   (void) cls;
505   if (NULL == rh)
506   {
507     /* Resolver service sent extra replies to query (after terminator)? Bad! */
508     GNUNET_break (0);
509     GNUNET_MQ_destroy (mq);
510     mq = NULL;
511     reconnect ();
512     return;
513   }
514   size = ntohs (msg->header.size);
515   if (size == sizeof (struct GNUNET_RESOLVER_ResponseMessage))
516   {
517     LOG (GNUNET_ERROR_TYPE_DEBUG,
518          "Received empty response from DNS service\n");
519     /* message contains not data, just header; end of replies */
520     /* check if request was canceled */
521     if (GNUNET_SYSERR != rh->was_transmitted)
522     {
523       /* no reverse lookup was successful, return IP as string */
524       if (NULL != rh->name_callback)
525       {
526         if (GNUNET_NO == rh->received_response)
527         {
528           nret = no_resolve (rh->af,
529                              &rh[1],
530                              rh->data_len);
531           rh->name_callback (rh->cls, nret);
532           GNUNET_free (nret);
533         }
534         /* finally, make termination call */
535         if (GNUNET_SYSERR != rh->was_transmitted)
536           rh->name_callback (rh->cls,
537                              NULL);
538       }
539       if ( (NULL != rh->addr_callback) &&
540            (GNUNET_SYSERR != rh->was_transmitted) )
541           rh->addr_callback (rh->cls,
542                              NULL,
543                              0);
544     }
545     rh->was_transmitted = GNUNET_NO;
546     GNUNET_RESOLVER_request_cancel (rh);
547     process_requests ();
548     return;
549   }
550   /* return reverse lookup results to caller */
551   if (NULL != rh->name_callback)
552   {
553     const char *hostname;
554
555     hostname = (const char *) &msg[1];
556     if (hostname[size - sizeof (struct GNUNET_RESOLVER_ResponseMessage) - 1] != '\0')
557     {
558       GNUNET_break (0);
559       if (GNUNET_SYSERR != rh->was_transmitted)
560         rh->name_callback (rh->cls,
561                            NULL);
562       rh->was_transmitted = GNUNET_NO;
563       GNUNET_RESOLVER_request_cancel (rh);
564       GNUNET_MQ_destroy (mq);
565       mq = NULL;
566       reconnect ();
567       return;
568     }
569     LOG (GNUNET_ERROR_TYPE_DEBUG,
570          "Resolver returns `%s' for IP `%s'.\n",
571          hostname,
572          GNUNET_a2s ((const void *) &rh[1],
573                      rh->data_len));
574     if (rh->was_transmitted != GNUNET_SYSERR)
575       rh->name_callback (rh->cls,
576                          hostname);
577     rh->received_response = GNUNET_YES;
578   }
579   /* return lookup results to caller */
580   if (NULL != rh->addr_callback)
581   {
582     struct sockaddr_in v4;
583     struct sockaddr_in6 v6;
584     const struct sockaddr *sa;
585     socklen_t salen;
586     const void *ip;
587     size_t ip_len;
588
589     ip = &msg[1];
590     ip_len = size - sizeof (struct GNUNET_RESOLVER_ResponseMessage);
591     if (ip_len == sizeof (struct in_addr))
592     {
593       memset (&v4, 0, sizeof (v4));
594       v4.sin_family = AF_INET;
595       v4.sin_addr = *(struct in_addr*) ip;
596 #if HAVE_SOCKADDR_IN_SIN_LEN
597       v4.sin_len = sizeof (v4);
598 #endif
599       salen = sizeof (v4);
600       sa = (const struct sockaddr *) &v4;
601     }
602     else if (ip_len == sizeof (struct in6_addr))
603     {
604       memset (&v6, 0, sizeof (v6));
605       v6.sin6_family = AF_INET6;
606       v6.sin6_addr = *(struct in6_addr*) ip;
607 #if HAVE_SOCKADDR_IN_SIN_LEN
608       v6.sin6_len = sizeof (v6);
609 #endif
610       salen = sizeof (v6);
611       sa = (const struct sockaddr *) &v6;
612     }
613     else
614     {
615       GNUNET_break (0);
616       if (GNUNET_SYSERR != rh->was_transmitted)
617         rh->addr_callback (rh->cls,
618                            NULL,
619                            0);
620       rh->was_transmitted = GNUNET_NO;
621       GNUNET_RESOLVER_request_cancel (rh);
622       GNUNET_MQ_destroy (mq);
623       mq = NULL;
624       reconnect ();
625       return;
626     }
627     LOG (GNUNET_ERROR_TYPE_DEBUG,
628          "Received IP from DNS service\n");
629     if (GNUNET_SYSERR != rh->was_transmitted)
630       rh->addr_callback (rh->cls,
631                          sa,
632                          salen);
633   }
634 }
635
636
637 /**
638  * We've been asked to lookup the address for a hostname and were
639  * given a valid numeric string.  Perform the callbacks for the
640  * numeric addresses.
641  *
642  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
643  */
644 static void
645 numeric_resolution (void *cls)
646 {
647   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
648   struct sockaddr_in v4;
649   struct sockaddr_in6 v6;
650   const char *hostname;
651
652   rh->task = NULL;
653   memset (&v4, 0, sizeof (v4));
654   v4.sin_family = AF_INET;
655 #if HAVE_SOCKADDR_IN_SIN_LEN
656   v4.sin_len = sizeof (v4);
657 #endif
658   memset (&v6, 0, sizeof (v6));
659   v6.sin6_family = AF_INET6;
660 #if HAVE_SOCKADDR_IN_SIN_LEN
661   v6.sin6_len = sizeof (v6);
662 #endif
663   hostname = (const char *) &rh[1];
664   if ( ( (rh->af == AF_UNSPEC) ||
665          (rh->af == AF_INET) ) &&
666        (1 == inet_pton (AF_INET,
667                         hostname,
668                         &v4.sin_addr)) )
669   {
670     rh->addr_callback (rh->cls,
671                        (const struct sockaddr *) &v4,
672                        sizeof (v4));
673     if ( (rh->af == AF_UNSPEC) &&
674          (GNUNET_SYSERR != rh->was_transmitted) &&
675          (1 == inet_pton (AF_INET6,
676                           hostname,
677                           &v6.sin6_addr)) )
678     {
679       /* this can happen on some systems IF "hostname" is "localhost" */
680       rh->addr_callback (rh->cls,
681                          (const struct sockaddr *) &v6,
682                          sizeof (v6));
683     }
684     if (GNUNET_SYSERR != rh->was_transmitted)
685       rh->addr_callback (rh->cls,
686                          NULL,
687                          0);
688     GNUNET_free (rh);
689     return;
690   }
691   if ( ( (rh->af == AF_UNSPEC) ||
692          (rh->af == AF_INET6) ) &&
693        (1 == inet_pton (AF_INET6,
694                         hostname,
695                         &v6.sin6_addr) ) )
696   {
697     rh->addr_callback (rh->cls,
698                        (const struct sockaddr *) &v6,
699                        sizeof (v6));
700     if (GNUNET_SYSERR != rh->was_transmitted)
701       rh->addr_callback (rh->cls,
702                          NULL,
703                          0);
704     GNUNET_free (rh);
705     return;
706   }
707   /* why are we here? this task should not have been scheduled! */
708   GNUNET_assert (0);
709   GNUNET_free (rh);
710 }
711
712
713 /**
714  * We've been asked to lookup the address for a hostname and were
715  * given a variant of "loopback".  Perform the callbacks for the
716  * respective loopback numeric addresses.
717  *
718  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
719  */
720 static void
721 loopback_resolution (void *cls)
722 {
723   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
724   struct sockaddr_in v4;
725   struct sockaddr_in6 v6;
726
727   rh->task = NULL;
728   memset (&v4, 0, sizeof (v4));
729   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
730   v4.sin_family = AF_INET;
731 #if HAVE_SOCKADDR_IN_SIN_LEN
732   v4.sin_len = sizeof (v4);
733 #endif
734   memset (&v6, 0, sizeof (v6));
735   v6.sin6_family = AF_INET6;
736 #if HAVE_SOCKADDR_IN_SIN_LEN
737   v6.sin6_len = sizeof (v6);
738 #endif
739   v6.sin6_addr = in6addr_loopback;
740   switch (rh->af)
741   {
742   case AF_INET:
743     rh->addr_callback (rh->cls,
744                        (const struct sockaddr *) &v4,
745                        sizeof (v4));
746     break;
747   case AF_INET6:
748     rh->addr_callback (rh->cls,
749                        (const struct sockaddr *) &v6,
750                        sizeof (v6));
751     break;
752   case AF_UNSPEC:
753     rh->addr_callback (rh->cls,
754                        (const struct sockaddr *) &v6,
755                        sizeof (v6));
756     rh->addr_callback (rh->cls,
757                        (const struct sockaddr *) &v4,
758                        sizeof (v4));
759
760     break;
761   default:
762     GNUNET_break (0);
763     break;
764   }
765   if (GNUNET_SYSERR != rh->was_transmitted)
766     rh->addr_callback (rh->cls,
767                        NULL,
768                        0);
769   LOG (GNUNET_ERROR_TYPE_DEBUG,
770        "Finished resolving hostname `%s'.\n",
771        (const char *) &rh[1]);
772   GNUNET_free (rh);
773 }
774
775
776 /**
777  * Now try to reconnect to the resolver service.
778  *
779  * @param cls NULL
780  */
781 static void
782 reconnect_task (void *cls)
783 {
784   struct GNUNET_MQ_MessageHandler handlers[] = {
785     GNUNET_MQ_hd_var_size (response,
786                            GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE,
787                            struct GNUNET_RESOLVER_ResponseMessage,
788                            NULL),
789     GNUNET_MQ_handler_end ()
790   };
791
792   (void) cls;
793   r_task = NULL;
794   if (NULL == req_head)
795     return;                     /* no work pending */
796   LOG (GNUNET_ERROR_TYPE_DEBUG,
797        "Trying to connect to DNS service\n");
798   mq = GNUNET_CLIENT_connect (resolver_cfg,
799                               "resolver",
800                               handlers,
801                               &mq_error_handler,
802                               NULL);
803   if (NULL == mq)
804   {
805     LOG (GNUNET_ERROR_TYPE_DEBUG,
806          "Failed to connect, will try again later\n");
807     reconnect ();
808     return;
809   }
810   process_requests ();
811 }
812
813
814 /**
815  * Adjust exponential back-off and reconnect to the service.
816  */
817 static void
818 reconnect ()
819 {
820   struct GNUNET_RESOLVER_RequestHandle *rh;
821
822   if (NULL != r_task)
823     return;
824   GNUNET_assert (NULL == mq);
825   if (NULL != (rh = req_head))
826   {
827     switch (rh->was_transmitted)
828     {
829     case GNUNET_NO:
830       /* nothing more to do */
831       break;
832     case GNUNET_YES:
833       /* disconnected, transmit again! */
834       rh->was_transmitted = GNUNET_NO;
835       break;
836     case GNUNET_SYSERR:
837       /* request was cancelled, remove entirely */
838       GNUNET_CONTAINER_DLL_remove (req_head,
839                                    req_tail,
840                                    rh);
841       GNUNET_free (rh);
842       check_disconnect ();
843       break;
844     default:
845       GNUNET_assert (0);
846       break;
847     }
848   }
849   LOG (GNUNET_ERROR_TYPE_DEBUG,
850        "Will try to connect to DNS service in %s\n",
851        GNUNET_STRINGS_relative_time_to_string (backoff,
852                                                GNUNET_YES));
853   GNUNET_assert (NULL != resolver_cfg);
854   r_task = GNUNET_SCHEDULER_add_delayed (backoff,
855                                          &reconnect_task,
856                                          NULL);
857   backoff = GNUNET_TIME_STD_BACKOFF (backoff);
858 }
859
860
861 /**
862  * A DNS resolution timed out. Notify the application.
863  *
864  * @param cls the `struct GNUNET_RESOLVER_RequestHandle *`
865  */
866 static void
867 handle_lookup_timeout (void *cls)
868 {
869   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
870
871   rh->task = NULL;
872   if (GNUNET_NO == rh->direction)
873   {
874     LOG (GNUNET_ERROR_TYPE_INFO,
875          _("Timeout trying to resolve hostname `%s'.\n"),
876          (const char *) &rh[1]);
877     if (NULL != rh->addr_callback)
878       rh->addr_callback (rh->cls,
879                          NULL,
880                          0);
881   }
882   else
883   {
884 #if !defined(GNUNET_CULL_LOGGING)
885     char buf[INET6_ADDRSTRLEN];
886
887     LOG (GNUNET_ERROR_TYPE_INFO,
888          _("Timeout trying to resolve IP address `%s'.\n"),
889          inet_ntop (rh->af,
890                     (const void *) &rh[1],
891                     buf,
892                     sizeof(buf)));
893 #endif
894     if (GNUNET_NO == rh->received_response)
895     {
896       char *nret;
897
898       nret = no_resolve (rh->af,
899                          &rh[1],
900                          rh->data_len);
901       if (NULL != rh->name_callback)
902         rh->name_callback (rh->cls, nret);
903       GNUNET_free (nret);
904     }
905     /* finally, make termination call */
906     if (NULL != rh->name_callback)
907       rh->name_callback (rh->cls,
908                          NULL);
909   }
910   rh->was_transmitted = GNUNET_NO;
911   GNUNET_RESOLVER_request_cancel (rh);
912   process_requests ();
913 }
914
915
916 /**
917  * Convert a string to one or more IP addresses.
918  *
919  * @param hostname the hostname to resolve
920  * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
921  * @param callback function to call with addresses
922  * @param callback_cls closure for @a callback
923  * @param timeout how long to try resolving
924  * @return handle that can be used to cancel the request, NULL on error
925  */
926 struct GNUNET_RESOLVER_RequestHandle *
927 GNUNET_RESOLVER_ip_get (const char *hostname,
928                         int af,
929                         struct GNUNET_TIME_Relative timeout,
930                         GNUNET_RESOLVER_AddressCallback callback,
931                         void *callback_cls)
932 {
933   struct GNUNET_RESOLVER_RequestHandle *rh;
934   size_t slen;
935   struct in_addr v4;
936   struct in6_addr v6;
937
938   slen = strlen (hostname) + 1;
939   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
940       GNUNET_MAX_MESSAGE_SIZE)
941   {
942     GNUNET_break (0);
943     return NULL;
944   }
945   LOG (GNUNET_ERROR_TYPE_DEBUG,
946        "Trying to resolve hostname `%s'.\n",
947        hostname);
948   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
949   rh->af = af;
950   rh->id = ++last_request_id;
951   rh->addr_callback = callback;
952   rh->cls = callback_cls;
953   GNUNET_memcpy (&rh[1],
954                  hostname,
955                  slen);
956   rh->data_len = slen;
957   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
958   rh->direction = GNUNET_NO;
959   /* first, check if this is a numeric address */
960   if ( ( (1 == inet_pton (AF_INET,
961                           hostname,
962                           &v4)) &&
963          ( (af == AF_INET) ||
964            (af == AF_UNSPEC) ) ) ||
965        ( (1 == inet_pton (AF_INET6,
966                           hostname,
967                           &v6)) &&
968          ( (af == AF_INET6) ||
969            (af == AF_UNSPEC)) ) )
970   {
971     rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution,
972                                          rh);
973     return rh;
974   }
975   /* then, check if this is a loopback address */
976   for (unsigned int i = 0;
977        NULL != loopback[i];
978        i++)
979     if (0 == strcasecmp (loopback[i],
980                          hostname))
981     {
982       rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution,
983                                            rh);
984       return rh;
985     }
986   if (GNUNET_OK != check_config ())
987   {
988     GNUNET_free (rh);
989     return NULL;
990   }
991   rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
992                                            &handle_lookup_timeout,
993                                            rh);
994   GNUNET_CONTAINER_DLL_insert_tail (req_head,
995                                     req_tail,
996                                     rh);
997   rh->was_queued = GNUNET_YES;
998   if (NULL != s_task)
999   {
1000     GNUNET_SCHEDULER_cancel (s_task);
1001     s_task = NULL;
1002   }
1003   process_requests ();
1004   return rh;
1005 }
1006
1007
1008 /**
1009  * We've been asked to convert an address to a string without
1010  * a reverse lookup, either because the client asked for it
1011  * or because the DNS lookup hit a timeout.  Do the numeric
1012  * conversion and invoke the callback.
1013  *
1014  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
1015  */
1016 static void
1017 numeric_reverse (void *cls)
1018 {
1019   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
1020   char *result;
1021
1022   rh->task = NULL;
1023   result = no_resolve (rh->af,
1024                        &rh[1],
1025                        rh->data_len);
1026   LOG (GNUNET_ERROR_TYPE_DEBUG,
1027        "Resolver returns `%s'.\n",
1028        result);
1029   if (NULL != result)
1030   {
1031     rh->name_callback (rh->cls,
1032                        result);
1033     GNUNET_free (result);
1034   }
1035   rh->name_callback (rh->cls,
1036                      NULL);
1037   if (NULL != rh->task)
1038   {
1039     GNUNET_SCHEDULER_cancel (rh->task);
1040     rh->task = NULL;
1041   }
1042   GNUNET_free (rh);
1043 }
1044
1045
1046 /**
1047  * Get an IP address as a string.
1048  *
1049  * @param sa host address
1050  * @param salen length of host address in @a sa
1051  * @param do_resolve use #GNUNET_NO to return numeric hostname
1052  * @param timeout how long to try resolving
1053  * @param callback function to call with hostnames
1054  *        last callback is NULL when finished
1055  * @param cls closure for @a callback
1056  * @return handle that can be used to cancel the request
1057  */
1058 struct GNUNET_RESOLVER_RequestHandle *
1059 GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1060                               socklen_t salen,
1061                               int do_resolve,
1062                               struct GNUNET_TIME_Relative timeout,
1063                               GNUNET_RESOLVER_HostnameCallback callback,
1064                               void *cls)
1065 {
1066   struct GNUNET_RESOLVER_RequestHandle *rh;
1067   size_t ip_len;
1068   const void *ip;
1069
1070   if (GNUNET_OK != check_config ())
1071   {
1072     LOG (GNUNET_ERROR_TYPE_ERROR,
1073          _("Resolver not configured correctly.\n"));
1074     return NULL;
1075   }
1076
1077   switch (sa->sa_family)
1078   {
1079   case AF_INET:
1080     GNUNET_assert (salen == sizeof (struct sockaddr_in));
1081     ip_len = sizeof (struct in_addr);
1082     ip = &((const struct sockaddr_in*)sa)->sin_addr;
1083     break;
1084   case AF_INET6:
1085     GNUNET_assert (salen == sizeof (struct sockaddr_in6));
1086     ip_len = sizeof (struct in6_addr);
1087     ip = &((const struct sockaddr_in6*)sa)->sin6_addr;
1088     break;
1089   default:
1090     GNUNET_break (0);
1091     return NULL;
1092   }
1093   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
1094   rh->name_callback = callback;
1095   rh->cls = cls;
1096   rh->af = sa->sa_family;
1097   rh->id = ++last_request_id;
1098   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1099   GNUNET_memcpy (&rh[1],
1100                  ip,
1101                  ip_len);
1102   rh->data_len = ip_len;
1103   rh->direction = GNUNET_YES;
1104   rh->received_response = GNUNET_NO;
1105   if (GNUNET_NO == do_resolve)
1106   {
1107     rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse,
1108                                          rh);
1109     return rh;
1110   }
1111   rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1112                                            &handle_lookup_timeout,
1113                                            rh);
1114   GNUNET_CONTAINER_DLL_insert_tail (req_head,
1115                                     req_tail,
1116                                     rh);
1117   rh->was_queued = GNUNET_YES;
1118   if (NULL != s_task)
1119   {
1120     GNUNET_SCHEDULER_cancel (s_task);
1121     s_task = NULL;
1122   }
1123   process_requests ();
1124   return rh;
1125 }
1126
1127
1128 /**
1129  * Get local fully qualified af name
1130  *
1131  * @return fqdn
1132  */
1133 char *
1134 GNUNET_RESOLVER_local_fqdn_get ()
1135 {
1136   char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1137
1138   if (0 != gethostname (hostname,
1139                         sizeof (hostname) - 1))
1140   {
1141     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1142                   "gethostname");
1143     return NULL;
1144   }
1145   LOG (GNUNET_ERROR_TYPE_DEBUG,
1146        "Resolving our FQDN `%s'\n",
1147        hostname);
1148 #if HAVE_GETADDRINFO
1149   {
1150     struct addrinfo *ai;
1151     int ret;
1152     char *rval;
1153
1154     if (0 != (ret = getaddrinfo (hostname,
1155                                  NULL,
1156                                  NULL,
1157                                  &ai)))
1158     {
1159       LOG (GNUNET_ERROR_TYPE_ERROR,
1160            _("Could not resolve our FQDN: %s\n"),
1161            gai_strerror (ret));
1162       return NULL;
1163     }
1164     if (NULL != ai->ai_canonname)
1165       rval = GNUNET_strdup (ai->ai_canonname);
1166     else
1167       rval = GNUNET_strdup (hostname);
1168     freeaddrinfo (ai);
1169     return rval;
1170   }
1171 #elif HAVE_GETHOSTBYNAME2
1172   {
1173     struct hostent *host;
1174
1175     host = gethostbyname2 (hostname,
1176                            AF_INET);
1177     if (NULL == host)
1178       host = gethostbyname2 (hostname,
1179                              AF_INET6);
1180     if (NULL == host)
1181       {
1182         LOG (GNUNET_ERROR_TYPE_ERROR,
1183              _("Could not resolve our FQDN: %s\n"),
1184              hstrerror (h_errno));
1185         return NULL;
1186       }
1187     return GNUNET_strdup (host->h_name);
1188   }
1189 #elif HAVE_GETHOSTBYNAME
1190   {
1191     struct hostent *host;
1192
1193     host = gethostbyname (hostname);
1194     if (NULL == host)
1195       {
1196         LOG (GNUNET_ERROR_TYPE_ERROR,
1197              _("Could not resolve our FQDN: %s\n"),
1198              hstrerror (h_errno));
1199         return NULL;
1200       }
1201     return GNUNET_strdup (host->h_name);
1202   }
1203 #else
1204   /* fallback: just hope name is already FQDN */
1205   return GNUNET_strdup (hostname);
1206 #endif
1207 }
1208
1209
1210 /**
1211  * Looking our own hostname.
1212  *
1213  * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
1214  * @param timeout how long to try resolving
1215  * @param callback function to call with addresses
1216  * @param cls closure for @a callback
1217  * @return handle that can be used to cancel the request, NULL on error
1218  */
1219 struct GNUNET_RESOLVER_RequestHandle *
1220 GNUNET_RESOLVER_hostname_resolve (int af,
1221                                   struct GNUNET_TIME_Relative timeout,
1222                                   GNUNET_RESOLVER_AddressCallback callback,
1223                                   void *cls)
1224 {
1225   char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1226
1227   if (0 != gethostname (hostname, sizeof (hostname) - 1))
1228   {
1229     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1230                   "gethostname");
1231     return NULL;
1232   }
1233   LOG (GNUNET_ERROR_TYPE_DEBUG,
1234        "Resolving our hostname `%s'\n",
1235        hostname);
1236   return GNUNET_RESOLVER_ip_get (hostname,
1237                                  af,
1238                                  timeout,
1239                                  callback,
1240                                  cls);
1241 }
1242
1243
1244 /**
1245  * Cancel a request that is still pending with the resolver.
1246  * Note that a client MUST NOT cancel a request that has
1247  * been completed (i.e, the callback has been called to
1248  * signal timeout or the final result).
1249  *
1250  * @param rh handle of request to cancel
1251  */
1252 void
1253 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh)
1254 {
1255   if (GNUNET_NO == rh->direction)
1256     LOG (GNUNET_ERROR_TYPE_DEBUG,
1257          "Asked to cancel request to resolve hostname `%s'.\n",
1258          (const char *) &rh[1]);
1259   if (NULL != rh->task)
1260   {
1261     GNUNET_SCHEDULER_cancel (rh->task);
1262     rh->task = NULL;
1263   }
1264   if (GNUNET_NO == rh->was_transmitted)
1265   {
1266     if (GNUNET_YES == rh->was_queued)
1267       GNUNET_CONTAINER_DLL_remove (req_head,
1268                                    req_tail,
1269                                    rh);
1270     GNUNET_free (rh);
1271     check_disconnect ();
1272     return;
1273   }
1274   GNUNET_assert (GNUNET_YES == rh->was_transmitted);
1275   rh->was_transmitted = GNUNET_SYSERR;  /* mark as cancelled */
1276   check_disconnect ();
1277 }
1278
1279
1280 /* end of resolver_api.c */