dac0ab16a5c63cd560335b376b6329370b3cce5a
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011-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 /**
22  * @file gns/gnunet-service-gns_resolver.c
23  * @brief GNU Name System resolver logic
24  * @author Martin Schanzenbach
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #if HAVE_LIBIDN2
29 #if HAVE_IDN2_H
30 #include <idn2.h>
31 #elif HAVE_IDN2_IDN2_H
32 #include <idn2/idn2.h>
33 #endif
34 #elif HAVE_LIBIDN
35 #if HAVE_IDNA_H
36 #include <idna.h>
37 #elif HAVE_IDN_IDNA_H
38 #include <idn/idna.h>
39 #endif
40 #endif
41 #include "gnunet_util_lib.h"
42 #include "gnunet_dnsstub_lib.h"
43 #include "gnunet_dht_service.h"
44 #include "gnunet_gnsrecord_lib.h"
45 #include "gnunet_namecache_service.h"
46 #include "gnunet_dns_service.h"
47 #include "gnunet_resolver_service.h"
48 #include "gnunet_revocation_service.h"
49 #include "gnunet_dnsparser_lib.h"
50 #include "gnunet_tun_lib.h"
51 #include "gnunet_gns_service.h"
52 #include "gns.h"
53 #include "gnunet-service-gns.h"
54 #include "gnunet-service-gns_resolver.h"
55 #include "gnunet_vpn_service.h"
56
57
58 /**
59  * Default DHT timeout for lookups.
60  */
61 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
62     GNUNET_TIME_UNIT_SECONDS, 60)
63
64 /**
65  * Default timeout for DNS lookups.
66  */
67 #define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
68     GNUNET_TIME_UNIT_SECONDS, 15)
69
70 /**
71  * Default timeout for VPN redirections.
72  */
73 #define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
74
75 /**
76  * DHT replication level
77  */
78 #define DHT_GNS_REPLICATION_LEVEL 10
79
80 /**
81  * How deep do we allow recursions to go before we abort?
82  */
83 #define MAX_RECURSION 256
84
85
86 /**
87  * DLL to hold the authority chain we had to pass in the resolution
88  * process.
89  */
90 struct AuthorityChain;
91
92
93 /**
94  * Element of a resolution process for looking up the
95  * responsible DNS server hostname in a GNS2DNS recursive
96  * resolution.
97  */
98 struct Gns2DnsPending
99 {
100   /**
101    * Kept in a DLL.
102    */
103   struct Gns2DnsPending *next;
104
105   /**
106    * Kept in a DLL.
107    */
108   struct Gns2DnsPending *prev;
109
110   /**
111    * Context this activity belongs with.
112    */
113   struct AuthorityChain *ac;
114
115   /**
116    * Handle for the resolution of the IP part of the
117    * GNS2DNS record.  Will return to us the addresses
118    * of the DNS resolver to use.
119    */
120   struct GNS_ResolverHandle *rh;
121
122   /**
123    * Handle for DNS resolution of the DNS nameserver.
124    */
125   struct GNUNET_RESOLVER_RequestHandle *dns_rh;
126
127   /**
128    * How many results did we get?
129    */
130   unsigned int num_results;
131 };
132
133
134 /**
135  * Handle to a currenty pending resolution.  On result (positive or
136  * negative) the #GNS_ResultProcessor is called.
137  */
138 struct GNS_ResolverHandle;
139
140
141 /**
142  * DLL to hold the authority chain we had to pass in the resolution
143  * process.
144  */
145 struct AuthorityChain
146 {
147   /**
148    * This is a DLL.
149    */
150   struct AuthorityChain *prev;
151
152   /**
153    * This is a DLL.
154    */
155   struct AuthorityChain *next;
156
157   /**
158    * Resolver handle this entry in the chain belongs to.
159    */
160   struct GNS_ResolverHandle *rh;
161
162   /**
163    * label/name corresponding to the authority
164    */
165   char *label;
166
167   /**
168    * #GNUNET_YES if the authority was a GNS authority,
169    * #GNUNET_NO if the authority was a DNS authority.
170    */
171   int gns_authority;
172
173   /**
174    * Information about the resolver authority for this label.
175    */
176   union
177   {
178     /**
179      * The zone of the GNS authority
180      */
181     struct GNUNET_CRYPTO_EcdsaPublicKey gns_authority;
182
183     struct
184     {
185       /**
186        * Domain of the DNS resolver that is the authority.
187        * (appended to construct the DNS name to resolve;
188        * this is NOT the DNS name of the DNS server!).
189        */
190       char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
191
192       /**
193        * List of resolutions of the 'ip' of the name server that
194        * are still pending.
195        */
196       struct Gns2DnsPending *gp_head;
197
198       /**
199        * Tail of list of resolutions of the 'ip' of the name server that
200        * are still pending.
201        */
202       struct Gns2DnsPending *gp_tail;
203
204       /**
205        * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
206        */
207       struct GNUNET_DNSSTUB_Context *dns_handle;
208
209       /**
210        * Did we succeed in getting an IP address for *any* of the DNS servers listed?
211        * Once we do, we can start with DNS queries.
212        */
213       int found;
214
215       /**
216        * Did we start the recursive resolution via DNS?
217        */
218       int launched;
219     } dns_authority;
220   } authority_info;
221 };
222
223
224 /**
225  * A result we got from DNS.
226  */
227 struct DnsResult
228 {
229   /**
230    * Kept in DLL.
231    */
232   struct DnsResult *next;
233
234   /**
235    * Kept in DLL.
236    */
237   struct DnsResult *prev;
238
239   /**
240    * Binary value stored in the DNS record (appended to this struct)
241    */
242   const void *data;
243
244   /**
245    * Expiration time for the DNS record, 0 if we didn't
246    * get anything useful (i.e. 'gethostbyname()' was used).
247    */
248   uint64_t expiration_time;
249
250   /**
251    * Number of bytes in @e data.
252    */
253   size_t data_size;
254
255   /**
256    * Type of the GNS/DNS record.
257    */
258   uint32_t record_type;
259 };
260
261
262 /**
263  * Closure for #vpn_allocation_cb.
264  */
265 struct VpnContext
266 {
267   /**
268    * Which resolution process are we processing.
269    */
270   struct GNS_ResolverHandle *rh;
271
272   /**
273    * Handle to the VPN request that we were performing.
274    */
275   struct GNUNET_VPN_RedirectionRequest *vpn_request;
276
277   /**
278    * Number of records serialized in @e rd_data.
279    */
280   unsigned int rd_count;
281
282   /**
283    * Serialized records.
284    */
285   char *rd_data;
286
287   /**
288    * Number of bytes in @e rd_data.
289    */
290   ssize_t rd_data_size;
291 };
292
293
294 /**
295  * Handle to a currenty pending resolution.  On result (positive or
296  * negative) the #GNS_ResultProcessor is called.
297  */
298 struct GNS_ResolverHandle
299 {
300   /**
301    * DLL
302    */
303   struct GNS_ResolverHandle *next;
304
305   /**
306    * DLL
307    */
308   struct GNS_ResolverHandle *prev;
309
310   /**
311    * The top-level GNS authoritative zone to query
312    */
313   struct GNUNET_CRYPTO_EcdsaPublicKey authority_zone;
314
315   /**
316    * called when resolution phase finishes
317    */
318   GNS_ResultProcessor proc;
319
320   /**
321    * closure passed to @e proc
322    */
323   void*proc_cls;
324
325   /**
326    * Handle for DHT lookups. should be NULL if no lookups are in progress
327    */
328   struct GNUNET_DHT_GetHandle *get_handle;
329
330   /**
331    * Handle to a VPN request, NULL if none is active.
332    */
333   struct VpnContext *vpn_ctx;
334
335   /**
336    * Socket for a DNS request, NULL if none is active.
337    */
338   struct GNUNET_DNSSTUB_RequestSocket *dns_request;
339
340   /**
341    * Handle for standard DNS resolution, NULL if none is active.
342    */
343   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
344
345   /**
346    * Pending Namecache lookup task
347    */
348   struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
349
350   /**
351    * Pending revocation check.
352    */
353   struct GNUNET_REVOCATION_Query *rev_check;
354
355   /**
356    * Heap node associated with this lookup.  Used to limit number of
357    * concurrent requests.
358    */
359   struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
360
361   /**
362    * DLL to store the authority chain
363    */
364   struct AuthorityChain *ac_head;
365
366   /**
367    * DLL to store the authority chain
368    */
369   struct AuthorityChain *ac_tail;
370
371   /**
372    * ID of a task associated with the resolution process.
373    */
374   struct GNUNET_SCHEDULER_Task *task_id;
375
376   /**
377    * The name to resolve
378    */
379   char *name;
380
381   /**
382    * Legacy Hostname to use if we encountered GNS2DNS record
383    * and thus can deduct the LEHO from that transition.
384    */
385   char *leho;
386
387   /**
388    * DLL of results we got from DNS.
389    */
390   struct DnsResult *dns_result_head;
391
392   /**
393    * DLL of results we got from DNS.
394    */
395   struct DnsResult *dns_result_tail;
396
397   /**
398    * Current offset in 'name' where we are resolving.
399    */
400   size_t name_resolution_pos;
401
402   /**
403    * Use only cache
404    */
405   enum GNUNET_GNS_LocalOptions options;
406
407   /**
408    * For SRV and TLSA records, the number of the
409    * protocol specified in the name.  0 if no protocol was given.
410    */
411   int protocol;
412
413   /**
414    * For SRV and TLSA records, the number of the
415    * service specified in the name.  0 if no service was given.
416    */
417   int service;
418
419   /**
420    * Desired type for the resolution.
421    */
422   int record_type;
423
424   /**
425    * We increment the loop limiter for each step in a recursive
426    * resolution.  If it passes our threshold (i.e. due to
427    * self-recursion in the resolution, i.e CNAME fun), we stop.
428    */
429   unsigned int loop_limiter;
430
431   /**
432    * 16 bit random ID we used in the @e dns_request.
433    */
434   uint16_t original_dns_id;
435 };
436
437
438 /**
439  * Active namestore caching operations.
440  */
441 struct CacheOps
442 {
443   /**
444    * Organized in a DLL.
445    */
446   struct CacheOps *next;
447
448   /**
449    * Organized in a DLL.
450    */
451   struct CacheOps *prev;
452
453   /**
454    * Pending Namestore caching task.
455    */
456   struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
457 };
458
459
460 /**
461  * Our handle to the namecache service
462  */
463 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
464
465 /**
466  * Our handle to the vpn service
467  */
468 static struct GNUNET_VPN_Handle *vpn_handle;
469
470 /**
471  * Resolver handle to the dht
472  */
473 static struct GNUNET_DHT_Handle *dht_handle;
474
475 /**
476  * Heap for limiting parallel DHT lookups
477  */
478 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
479
480 /**
481  * Maximum amount of parallel queries to the DHT
482  */
483 static unsigned long long max_allowed_background_queries;
484
485 /**
486  * Head of resolver lookup list
487  */
488 static struct GNS_ResolverHandle *rlh_head;
489
490 /**
491  * Tail of resolver lookup list
492  */
493 static struct GNS_ResolverHandle *rlh_tail;
494
495 /**
496  * Organized in a DLL.
497  */
498 static struct CacheOps *co_head;
499
500 /**
501  * Organized in a DLL.
502  */
503 static struct CacheOps *co_tail;
504
505 /**
506  * Use namecache
507  */
508 static int disable_cache;
509
510 /**
511  * Global configuration.
512  */
513 static const struct GNUNET_CONFIGURATION_Handle *cfg;
514
515
516 /**
517  * Determine if this name is canonical (is a legal name in a zone, without delegation);
518  * note that we do not test that the name does not contain illegal characters, we only
519  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
520  * even though they consist of multiple labels.
521  *
522  * Examples:
523  * a.b.gnu   = not canonical
524  * a         = canonical
525  * _foo._srv = canonical
526  * _f.bar    = not canonical
527  *
528  * @param name the name to test
529  * @return #GNUNET_YES if canonical
530  */
531 /* dead, but keep for now */ int
532 is_canonical (const char *name)
533 {
534   const char *pos;
535   const char *dot;
536
537   if (NULL == strchr (name,
538                       (unsigned char) '.'))
539     return GNUNET_YES;
540   if ('_' != name[0])
541     return GNUNET_NO;
542   pos = &name[1];
543   while (NULL != (dot = strchr (pos,
544                                 (unsigned char) '.')))
545     if ('_' != dot[1])
546       return GNUNET_NO;
547     else
548       pos = dot + 1;
549   return GNUNET_YES;
550 }
551
552
553 /* ************************** Resolution **************************** */
554
555 /**
556  * Expands a name ending in .+ with the zone of origin.
557  *
558  * @param rh resolution context
559  * @param name name to modify (to be free'd or returned)
560  * @return updated name
561  */
562 static char *
563 translate_dot_plus (struct GNS_ResolverHandle *rh,
564                     char *name)
565 {
566   char *ret;
567   size_t s_len = strlen (name);
568
569   if (0 != strcmp (&name[s_len - 2],
570                    ".+"))
571     return name; /* did not end in ".+" */
572   GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
573   GNUNET_asprintf (&ret,
574                    "%.*s.%s",
575                    (int) (s_len - 2),
576                    name,
577                    GNUNET_GNSRECORD_pkey_to_zkey (
578                      &rh->ac_tail->authority_info.gns_authority));
579   GNUNET_free (name);
580   return ret;
581 }
582
583
584 /**
585  * Wrapper around #GNS_resolver_lookup_cancel() as a task.
586  * Used for delayed cleanup so we can unwind the stack first.
587  *
588  * @param cls the `struct GNS_ResolverHandle`
589  */
590 static void
591 GNS_resolver_lookup_cancel_ (void *cls)
592 {
593   struct GNS_ResolverHandle *rh = cls;
594
595   rh->task_id = NULL;
596   GNS_resolver_lookup_cancel (rh);
597 }
598
599
600 /**
601  * Function called to asynchronously fail a resolution.
602  *
603  * @param rh the resolution to fail
604  */
605 static void
606 fail_resolution (struct GNS_ResolverHandle *rh)
607 {
608   rh->proc (rh->proc_cls,
609             0,
610             NULL);
611   GNUNET_assert (NULL == rh->task_id);
612   rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
613                                           rh);
614 }
615
616
617 /**
618  * Function called when a resolution times out.
619  *
620  * @param cls the `struct GNS_ResolverHandle`
621  */
622 static void
623 timeout_resolution (void *cls)
624 {
625   struct GNS_ResolverHandle *rh = cls;
626
627   rh->task_id = NULL;
628   fail_resolution (rh);
629 }
630
631
632 /**
633  * Get the next, rightmost label from the name that we are trying to resolve,
634  * and update the resolution position accordingly.  Labels usually consist
635  * of up to 63 characters without a period ("."); however, we use a special
636  * convention to support SRV and TLSA records where the domain name
637  * includes an encoding for a service and protocol in the name.  The
638  * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
639  * special case we include the "_Service._Proto" in the rightmost label.
640  * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
641  * the label "_443._tcp.foo".  The special case is detected by the
642  * presence of labels beginning with an underscore.  Whenever a label
643  * begins with an underscore, it is combined with the label to its right
644  * (and the "." is preserved).
645  *
646  * @param rh handle to the resolution operation to get the next label from
647  * @return NULL if there are no more labels
648  */
649 static char *
650 resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
651 {
652   const char *rp;
653   const char *dot;
654   size_t len;
655   char *ret;
656   char *srv_name;
657   char *proto_name;
658   struct protoent *pe;
659   struct servent *se;
660
661   if (0 == rh->name_resolution_pos)
662     return NULL;
663   dot = memrchr (rh->name,
664                  (int) '.',
665                  rh->name_resolution_pos);
666   if (NULL == dot)
667   {
668     /* done, this was the last one */
669     len = rh->name_resolution_pos;
670     rp = rh->name;
671     rh->name_resolution_pos = 0;
672   }
673   else
674   {
675     /* advance by one label */
676     len = rh->name_resolution_pos - (dot - rh->name) - 1;
677     rp = dot + 1;
678     rh->name_resolution_pos = dot - rh->name;
679   }
680   rh->protocol = 0;
681   rh->service = 0;
682   ret = GNUNET_strndup (rp, len);
683   /* If we have labels starting with underscore with label on
684    * the right (SRV/DANE/BOX case), determine port/protocol;
685    * The format of `rh->name` must be "_PORT._PROTOCOL".
686    */
687   if (('_' == rh->name[0]) &&
688       (NULL != (dot = memrchr (rh->name,
689                                (int) '.',
690                                rh->name_resolution_pos))) &&
691       ('_' == dot[1]) &&
692       (NULL == memrchr (rh->name,
693                         (int) '.',
694                         dot - rh->name)))
695   {
696     srv_name = GNUNET_strndup (&rh->name[1],
697                                (dot - rh->name) - 1);
698     proto_name = GNUNET_strndup (&dot[2],
699                                  rh->name_resolution_pos - (dot - rh->name)
700                                  - 1);
701     rh->name_resolution_pos = 0;
702     pe = getprotobyname (proto_name);
703     if (NULL == pe)
704     {
705       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
706                   _ ("Protocol `%s' unknown, skipping labels.\n"),
707                   proto_name);
708       GNUNET_free (proto_name);
709       GNUNET_free (srv_name);
710       return ret;
711     }
712     se = getservbyname (srv_name,
713                         proto_name);
714     if (NULL == se)
715     {
716       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
717                   _ (
718                     "Service `%s' unknown for protocol `%s', skipping labels.\n"),
719                   srv_name,
720                   proto_name);
721       GNUNET_free (proto_name);
722       GNUNET_free (srv_name);
723       return ret;
724     }
725     rh->protocol = pe->p_proto;
726     rh->service = se->s_port;
727     GNUNET_free (proto_name);
728     GNUNET_free (srv_name);
729   }
730   return ret;
731 }
732
733
734 /**
735  * Gives the cummulative result obtained to the callback and clean up the request.
736  *
737  * @param rh resolution process that has culminated in a result
738  */
739 static void
740 transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
741 {
742   struct DnsResult *pos;
743   unsigned int n;
744   unsigned int i;
745
746   n = 0;
747   for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
748     n++;
749   {
750     struct GNUNET_GNSRECORD_Data rd[n];
751
752     i = 0;
753     for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
754     {
755       rd[i].data = pos->data;
756       rd[i].data_size = pos->data_size;
757       rd[i].record_type = pos->record_type;
758       if (0 == pos->expiration_time)
759       {
760         rd[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
761         rd[i].expiration_time = 0;
762       }
763       else
764       {
765         rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
766         rd[i].expiration_time = pos->expiration_time;
767       }
768       i++;
769     }
770     GNUNET_assert (i == n);
771     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772                 "Transmitting standard DNS result with %u records\n",
773                 n);
774     rh->proc (rh->proc_cls,
775               n,
776               rd);
777   }
778   GNS_resolver_lookup_cancel (rh);
779 }
780
781
782 /**
783  * Add a result from DNS to the records to be returned to the application.
784  *
785  * @param rh resolution request to extend with a result
786  * @param expiration_time expiration time for the answer
787  * @param record_type DNS record type of the answer
788  * @param data_size number of bytes in @a data
789  * @param data binary data to return in DNS record
790  */
791 static void
792 add_dns_result (struct GNS_ResolverHandle *rh,
793                 uint64_t expiration_time,
794                 uint32_t record_type,
795                 size_t data_size,
796                 const void *data)
797 {
798   struct DnsResult *res;
799
800   res = GNUNET_malloc (sizeof(struct DnsResult) + data_size);
801   res->expiration_time = expiration_time;
802   res->data_size = data_size;
803   res->record_type = record_type;
804   res->data = &res[1];
805   GNUNET_memcpy (&res[1],
806                  data,
807                  data_size);
808   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
809                                rh->dns_result_tail,
810                                res);
811 }
812
813
814 /**
815  * We had to do a DNS lookup.  Convert the result (if any) and return
816  * it.
817  *
818  * @param cls closure with the `struct GNS_ResolverHandle`
819  * @param addr one of the addresses of the host, NULL for the last address
820  * @param addrlen length of the address
821  */
822 static void
823 handle_dns_result (void *cls,
824                    const struct sockaddr *addr,
825                    socklen_t addrlen)
826 {
827   struct GNS_ResolverHandle *rh = cls;
828   const struct sockaddr_in *sa4;
829   const struct sockaddr_in6 *sa6;
830
831   if (NULL == addr)
832   {
833     rh->std_resolve = NULL;
834     transmit_lookup_dns_result (rh);
835     return;
836   }
837   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838               "Received %u bytes of DNS IP data\n",
839               addrlen);
840   switch (addr->sa_family)
841   {
842   case AF_INET:
843     sa4 = (const struct sockaddr_in *) addr;
844     add_dns_result (rh,
845                     0 /* expiration time is unknown */,
846                     GNUNET_DNSPARSER_TYPE_A,
847                     sizeof(struct in_addr),
848                     &sa4->sin_addr);
849     break;
850
851   case AF_INET6:
852     sa6 = (const struct sockaddr_in6 *) addr;
853     add_dns_result (rh,
854                     0 /* expiration time is unknown */,
855                     GNUNET_DNSPARSER_TYPE_AAAA,
856                     sizeof(struct in6_addr),
857                     &sa6->sin6_addr);
858     break;
859
860   default:
861     GNUNET_break (0);
862     break;
863   }
864 }
865
866
867 /**
868  * Task scheduled to continue with the resolution process.
869  *
870  * @param cls the 'struct GNS_ResolverHandle' of the resolution
871  * @param tc task context
872  */
873 static void
874 recursive_resolution (void *cls);
875
876
877 /**
878  * Begin the resolution process from 'name', starting with
879  * the identification of the zone specified by 'name'.
880  *
881  * @param cls closure with `struct GNS_ResolverHandle *rh`
882  */
883 static void
884 start_resolver_lookup (void *cls);
885
886
887 /**
888  * Function called with the result of a DNS resolution.
889  *
890  * @param cls the request handle of the resolution that
891  *        we were attempting to make
892  * @param dns dns response, never NULL
893  * @param dns_len number of bytes in @a dns
894  */
895 static void
896 dns_result_parser (void *cls,
897                    const struct GNUNET_TUN_DnsHeader *dns,
898                    size_t dns_len)
899 {
900   struct GNS_ResolverHandle *rh = cls;
901   struct GNUNET_DNSPARSER_Packet *p;
902   const struct GNUNET_DNSPARSER_Record *rec;
903   unsigned int rd_count;
904
905   if (NULL == dns)
906   {
907     rh->dns_request = NULL;
908     GNUNET_SCHEDULER_cancel (rh->task_id);
909     rh->task_id = NULL;
910     fail_resolution (rh);
911     return;
912   }
913   if (rh->original_dns_id != dns->id)
914   {
915     /* DNS answer, but for another query */
916     return;
917   }
918   p = GNUNET_DNSPARSER_parse ((const char *) dns,
919                               dns_len);
920   if (NULL == p)
921   {
922     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
923                 _ ("Failed to parse DNS response\n"));
924     return;
925   }
926
927   /* We got a result from DNS */
928   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929               "Received DNS response for `%s' with %u answers\n",
930               rh->ac_tail->label,
931               (unsigned int) p->num_answers);
932   if ((p->num_answers > 0) &&
933       (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
934       (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
935   {
936     int af;
937
938     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
939                 "Got CNAME `%s' from DNS for `%s'\n",
940                 p->answers[0].data.hostname,
941                 rh->name);
942     if (NULL != rh->std_resolve)
943     {
944       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
945                   "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
946                   rh->name);
947       GNUNET_RESOLVER_request_cancel (rh->std_resolve);
948     }
949     GNUNET_free (rh->name);
950     rh->name = GNUNET_strdup (p->answers[0].data.hostname);
951     rh->name_resolution_pos = strlen (rh->name);
952     switch (rh->record_type)
953     {
954     case GNUNET_DNSPARSER_TYPE_A:
955       af = AF_INET;
956       break;
957
958     case GNUNET_DNSPARSER_TYPE_AAAA:
959       af = AF_INET6;
960       break;
961
962     default:
963       af = AF_UNSPEC;
964       break;
965     }
966     if (NULL != rh->leho)
967       add_dns_result (rh,
968                       GNUNET_TIME_UNIT_HOURS.rel_value_us,
969                       GNUNET_GNSRECORD_TYPE_LEHO,
970                       strlen (rh->leho),
971                       rh->leho);
972     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
973                                               af,
974                                               DNS_LOOKUP_TIMEOUT,
975                                               &handle_dns_result,
976                                               rh);
977     GNUNET_DNSPARSER_free_packet (p);
978     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
979     rh->dns_request = NULL;
980     return;
981   }
982
983   /* convert from (parsed) DNS to (binary) GNS format! */
984   rd_count = p->num_answers + p->num_authority_records
985              + p->num_additional_records;
986   {
987     struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
988     int skip;
989     char buf[UINT16_MAX];
990     size_t buf_off;
991     size_t buf_start;
992
993     buf_off = 0;
994     skip = 0;
995     memset (rd,
996             0,
997             sizeof(rd));
998     for (unsigned int i = 0; i < rd_count; i++)
999     {
1000       if (i < p->num_answers)
1001         rec = &p->answers[i];
1002       else if (i < p->num_answers + p->num_authority_records)
1003         rec = &p->authority_records[i - p->num_answers];
1004       else
1005         rec = &p->additional_records[i - p->num_answers
1006                                      - p->num_authority_records];
1007       /* As we copied the full DNS name to 'rh->ac_tail->label', this
1008          should be the correct check to see if this record is actually
1009          a record for our label... */
1010       if (0 != strcmp (rec->name,
1011                        rh->ac_tail->label))
1012       {
1013         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014                     "Dropping record `%s', does not match desired name `%s'\n",
1015                     rec->name,
1016                     rh->ac_tail->label);
1017         skip++;
1018         continue;
1019       }
1020       rd[i - skip].record_type = rec->type;
1021       rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1022       switch (rec->type)
1023       {
1024       case GNUNET_DNSPARSER_TYPE_A:
1025         if (rec->data.raw.data_len != sizeof(struct in_addr))
1026         {
1027           GNUNET_break_op (0);
1028           skip++;
1029           continue;
1030         }
1031         rd[i - skip].data_size = rec->data.raw.data_len;
1032         rd[i - skip].data = rec->data.raw.data;
1033         break;
1034
1035       case GNUNET_DNSPARSER_TYPE_AAAA:
1036         if (rec->data.raw.data_len != sizeof(struct in6_addr))
1037         {
1038           GNUNET_break_op (0);
1039           skip++;
1040           continue;
1041         }
1042         rd[i - skip].data_size = rec->data.raw.data_len;
1043         rd[i - skip].data = rec->data.raw.data;
1044         break;
1045
1046       case GNUNET_DNSPARSER_TYPE_CNAME:
1047       case GNUNET_DNSPARSER_TYPE_PTR:
1048       case GNUNET_DNSPARSER_TYPE_NS:
1049         buf_start = buf_off;
1050         if (GNUNET_OK !=
1051             GNUNET_DNSPARSER_builder_add_name (buf,
1052                                                sizeof(buf),
1053                                                &buf_off,
1054                                                rec->data.hostname))
1055         {
1056           GNUNET_break (0);
1057           skip++;
1058           continue;
1059         }
1060         rd[i - skip].data_size = buf_off - buf_start;
1061         rd[i - skip].data = &buf[buf_start];
1062         break;
1063
1064       case GNUNET_DNSPARSER_TYPE_SOA:
1065         buf_start = buf_off;
1066         if (GNUNET_OK !=
1067             GNUNET_DNSPARSER_builder_add_soa (buf,
1068                                               sizeof(buf),
1069                                               &buf_off,
1070                                               rec->data.soa))
1071         {
1072           GNUNET_break (0);
1073           skip++;
1074           continue;
1075         }
1076         rd[i - skip].data_size = buf_off - buf_start;
1077         rd[i - skip].data = &buf[buf_start];
1078         break;
1079
1080       case GNUNET_DNSPARSER_TYPE_MX:
1081         buf_start = buf_off;
1082         if (GNUNET_OK !=
1083             GNUNET_DNSPARSER_builder_add_mx (buf,
1084                                              sizeof(buf),
1085                                              &buf_off,
1086                                              rec->data.mx))
1087         {
1088           GNUNET_break (0);
1089           skip++;
1090           continue;
1091         }
1092         rd[i - skip].data_size = buf_off - buf_start;
1093         rd[i - skip].data = &buf[buf_start];
1094         break;
1095
1096       case GNUNET_DNSPARSER_TYPE_SRV:
1097         buf_start = buf_off;
1098         if (GNUNET_OK !=
1099             GNUNET_DNSPARSER_builder_add_srv (buf,
1100                                               sizeof(buf),
1101                                               &buf_off,
1102                                               rec->data.srv))
1103         {
1104           GNUNET_break (0);
1105           skip++;
1106           continue;
1107         }
1108         rd[i - skip].data_size = buf_off - buf_start;
1109         rd[i - skip].data = &buf[buf_start];
1110         break;
1111
1112       default:
1113         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1114                     _ ("Skipping record of unsupported type %d\n"),
1115                     rec->type);
1116         skip++;
1117         continue;
1118       }
1119     }   /* end of for all records in answer */
1120     if (NULL != rh->leho)
1121     {
1122       rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1123       rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1124       rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1125       rd[rd_count - skip].data = rh->leho;
1126       rd[rd_count - skip].data_size = strlen (rh->leho);
1127       skip--;   /* skip one LESS */
1128       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1129                   "Adding LEHO %s\n",
1130                   rh->leho);
1131     }
1132     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133                 "Returning DNS response for `%s' with %u answers\n",
1134                 rh->ac_tail->label,
1135                 (unsigned int) (rd_count - skip));
1136     rh->proc (rh->proc_cls,
1137               rd_count - skip,
1138               rd);
1139     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1140     rh->dns_request = NULL;
1141   }
1142   GNUNET_DNSPARSER_free_packet (p);
1143   if (NULL != rh->task_id)
1144     GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1145   rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1146                                           rh);
1147 }
1148
1149
1150 /**
1151  * Perform recursive DNS resolution.  Asks the given DNS resolver to
1152  * resolve "rh->dns_name", possibly recursively proceeding following
1153  * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1154  * we find the answer.
1155  *
1156  * @param rh resolution information
1157  */
1158 static void
1159 recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1160 {
1161   struct AuthorityChain *ac;
1162   struct GNUNET_DNSPARSER_Query *query;
1163   struct GNUNET_DNSPARSER_Packet *p;
1164   char *dns_request;
1165   size_t dns_request_length;
1166   int ret;
1167
1168   ac = rh->ac_tail;
1169   GNUNET_assert (NULL != ac);
1170   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171               "Starting DNS lookup for `%s'\n",
1172               ac->label);
1173   GNUNET_assert (GNUNET_NO == ac->gns_authority);
1174   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1175   query->name = GNUNET_strdup (ac->label);
1176   query->type = rh->record_type;
1177   query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1178   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1179   p->queries = query;
1180   p->num_queries = 1;
1181   p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1182                                                UINT16_MAX);
1183   p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1184   p->flags.recursion_desired = 1;
1185   ret = GNUNET_DNSPARSER_pack (p,
1186                                1024,
1187                                &dns_request,
1188                                &dns_request_length);
1189   if (GNUNET_OK != ret)
1190   {
1191     GNUNET_break (0);
1192     rh->proc (rh->proc_cls,
1193               0,
1194               NULL);
1195     GNUNET_assert (NULL == rh->task_id);
1196     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1197                                             rh);
1198   }
1199   else
1200   {
1201     rh->original_dns_id = p->id;
1202     GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1203     GNUNET_assert (NULL == rh->dns_request);
1204     rh->leho = GNUNET_strdup (ac->label);
1205     rh->dns_request = GNUNET_DNSSTUB_resolve (
1206       ac->authority_info.dns_authority.dns_handle,
1207       dns_request,
1208       dns_request_length,
1209       &dns_result_parser,
1210       rh);
1211     rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1212                                                 &timeout_resolution,
1213                                                 rh);
1214   }
1215   if (GNUNET_SYSERR != ret)
1216     GNUNET_free (dns_request);
1217   GNUNET_DNSPARSER_free_packet (p);
1218 }
1219
1220
1221 /**
1222  * We encountered a CNAME record during our resolution.
1223  * Merge it into our chain.
1224  *
1225  * @param rh resolution we are performing
1226  * @param cname value of the cname record we got for the current
1227  *        authority chain tail
1228  */
1229 static void
1230 handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1231                          const char *cname)
1232 {
1233   size_t nlen;
1234   char *res;
1235   const char *tld;
1236   struct AuthorityChain *ac;
1237   int af;
1238   struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1239
1240   nlen = strlen (cname);
1241   tld = GNS_get_tld (cname);
1242   if (0 == strcmp ("+", tld))
1243   {
1244     /* CNAME resolution continues relative to current domain */
1245     if (0 == rh->name_resolution_pos)
1246     {
1247       res = GNUNET_strndup (cname, nlen - 2);
1248       rh->name_resolution_pos = nlen - 2;
1249     }
1250     else
1251     {
1252       GNUNET_asprintf (&res,
1253                        "%.*s.%.*s",
1254                        (int) rh->name_resolution_pos,
1255                        rh->name,
1256                        (int) (nlen - 2),
1257                        cname);
1258       rh->name_resolution_pos = strlen (res);
1259     }
1260     GNUNET_free (rh->name);
1261     rh->name = res;
1262     ac = GNUNET_new (struct AuthorityChain);
1263     ac->rh = rh;
1264     ac->gns_authority = GNUNET_YES;
1265     ac->authority_info.gns_authority =
1266       rh->ac_tail->authority_info.gns_authority;
1267     ac->label = resolver_lookup_get_next_label (rh);
1268     /* add AC to tail */
1269     GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1270                                       rh->ac_tail,
1271                                       ac);
1272     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1273                                             rh);
1274     return;
1275   }
1276   if (GNUNET_OK == GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone))
1277   {
1278     /* CNAME resolution continues relative to current domain */
1279     if (0 == rh->name_resolution_pos)
1280     {
1281       GNUNET_asprintf (&res,
1282                        "%.*s",
1283                        strlen (cname) - (strlen (tld) + 1),
1284                        cname);
1285     }
1286     else
1287     {
1288       GNUNET_asprintf (&res,
1289                        "%.*s.%.*s",
1290                        (int) rh->name_resolution_pos,
1291                        rh->name,
1292                        (int) strlen (cname) - (strlen (tld) + 1),
1293                        cname);
1294     }
1295     rh->name_resolution_pos = strlen (res);
1296     GNUNET_free (rh->name);
1297     rh->name = res;
1298     ac = GNUNET_new (struct AuthorityChain);
1299     ac->rh = rh;
1300     ac->gns_authority = GNUNET_YES;
1301     ac->authority_info.gns_authority = zone;
1302     ac->label = resolver_lookup_get_next_label (rh);
1303     /* add AC to tail */
1304     GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1305                                       rh->ac_tail,
1306                                       ac);
1307     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1308                                             rh);
1309     return;
1310   }
1311
1312   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1313               "Got CNAME `%s' from GNS for `%s'\n",
1314               cname,
1315               rh->name);
1316   if (NULL != rh->std_resolve)
1317   {
1318     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1319                 "Multiple CNAME results from GNS resolving `%s'! Not really allowed...\n",
1320                 rh->name);
1321     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1322   }
1323   /* name is absolute, go to DNS */
1324   GNUNET_free (rh->name);
1325   rh->name = GNUNET_strdup (cname);
1326   rh->name_resolution_pos = strlen (rh->name);
1327   switch (rh->record_type)
1328   {
1329   case GNUNET_DNSPARSER_TYPE_A:
1330     af = AF_INET;
1331     break;
1332
1333   case GNUNET_DNSPARSER_TYPE_AAAA:
1334     af = AF_INET6;
1335     break;
1336
1337   default:
1338     af = AF_UNSPEC;
1339     break;
1340   }
1341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342               "Doing standard DNS lookup for `%s'\n",
1343               rh->name);
1344   rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1345                                             af,
1346                                             DNS_LOOKUP_TIMEOUT,
1347                                             &handle_dns_result,
1348                                             rh);
1349 }
1350
1351
1352 /**
1353  * Process a records that were decrypted from a block.
1354  *
1355  * @param cls closure with the 'struct GNS_ResolverHandle'
1356  * @param rd_count number of entries in @a rd array
1357  * @param rd array of records with data to store
1358  */
1359 static void
1360 handle_gns_resolution_result (void *cls,
1361                               unsigned int rd_count,
1362                               const struct GNUNET_GNSRECORD_Data *rd);
1363
1364
1365 /**
1366  * Callback invoked from the VPN service once a redirection is
1367  * available.  Provides the IP address that can now be used to
1368  * reach the requested destination.  Replaces the "VPN" record
1369  * with the respective A/AAAA record and continues processing.
1370  *
1371  * @param cls closure
1372  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
1373  *                will match 'result_af' from the request
1374  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
1375  *                that the VPN allocated for the redirection;
1376  *                traffic to this IP will now be redirected to the
1377  *                specified target peer; NULL on error
1378  */
1379 static void
1380 vpn_allocation_cb (void *cls,
1381                    int af,
1382                    const void *address)
1383 {
1384   struct VpnContext *vpn_ctx = cls;
1385   struct GNS_ResolverHandle *rh = vpn_ctx->rh;
1386   struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
1387   unsigned int i;
1388
1389   vpn_ctx->vpn_request = NULL;
1390   rh->vpn_ctx = NULL;
1391   GNUNET_assert (GNUNET_OK ==
1392                  GNUNET_GNSRECORD_records_deserialize (
1393                    (size_t) vpn_ctx->rd_data_size,
1394                    vpn_ctx->rd_data,
1395                    vpn_ctx->rd_count,
1396                    rd));
1397   for (i = 0; i < vpn_ctx->rd_count; i++)
1398   {
1399     if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
1400     {
1401       switch (af)
1402       {
1403       case AF_INET:
1404         rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
1405         rd[i].data_size = sizeof(struct in_addr);
1406         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
1407           VPN_TIMEOUT).abs_value_us;
1408         rd[i].flags = 0;
1409         rd[i].data = address;
1410         break;
1411
1412       case AF_INET6:
1413         rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
1414         rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
1415           VPN_TIMEOUT).abs_value_us;
1416         rd[i].flags = 0;
1417         rd[i].data = address;
1418         rd[i].data_size = sizeof(struct in6_addr);
1419         break;
1420
1421       default:
1422         GNUNET_assert (0);
1423       }
1424       break;
1425     }
1426   }
1427   GNUNET_assert (i < vpn_ctx->rd_count);
1428   if (0 == vpn_ctx->rd_count)
1429     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1430                 _ ("VPN returned empty result for `%s'\n"),
1431                 rh->name);
1432   handle_gns_resolution_result (rh,
1433                                 vpn_ctx->rd_count,
1434                                 rd);
1435   GNUNET_free (vpn_ctx->rd_data);
1436   GNUNET_free (vpn_ctx);
1437 }
1438
1439
1440 /**
1441  * We have resolved one or more of the nameservers for a
1442  * GNS2DNS lookup.  Once we have some of them, begin using
1443  * the DNSSTUB resolver.
1444  *
1445  * @param ac context for GNS2DNS resolution
1446  */
1447 static void
1448 continue_with_gns2dns (struct AuthorityChain *ac)
1449 {
1450   struct GNS_ResolverHandle *rh = ac->rh;
1451
1452   if ((NULL != ac->authority_info.dns_authority.gp_head) &&
1453       (GNUNET_NO == ac->authority_info.dns_authority.found))
1454     return; /* more pending and none found yet */
1455   if (GNUNET_NO == ac->authority_info.dns_authority.found)
1456   {
1457     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1458                 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1459                 ac->authority_info.dns_authority.name);
1460     fail_resolution (rh);
1461     return;
1462   }
1463   if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1464     return; /* already running, do not launch again! */
1465   /* recurse */
1466   ac->authority_info.dns_authority.launched = GNUNET_YES;
1467   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1468               "Will continue resolution using DNS to resolve `%s'\n",
1469               ac->label);
1470   GNUNET_assert (NULL == rh->task_id);
1471   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1472                                           rh);
1473 }
1474
1475
1476 /**
1477  * We've resolved the IP address for the DNS resolver to use
1478  * after encountering a GNS2DNS record.
1479  *
1480  * @param cls the `struct Gns2DnsPending` used for this request
1481  * @param rd_count number of records in @a rd
1482  * @param rd addresses for the DNS resolver  (presumably)
1483  */
1484 static void
1485 handle_gns2dns_result (void *cls,
1486                        unsigned int rd_count,
1487                        const struct GNUNET_GNSRECORD_Data *rd)
1488 {
1489   struct Gns2DnsPending *gp = cls;
1490   struct AuthorityChain *ac = gp->ac;
1491
1492   GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1493                                ac->authority_info.dns_authority.gp_tail,
1494                                gp);
1495   /* enable cleanup of 'rh' handle that automatically comes after we return,
1496      and which expects 'rh' to be in the #rlh_head DLL. */
1497   if (NULL != gp->rh)
1498   {
1499     GNUNET_CONTAINER_DLL_insert (rlh_head,
1500                                  rlh_tail,
1501                                  gp->rh);
1502     gp->rh = NULL;
1503   }
1504   GNUNET_free (gp);
1505   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1506               "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1507               rd_count);
1508   /* find suitable A/AAAA record */
1509   for (unsigned int j = 0; j < rd_count; j++)
1510   {
1511     switch (rd[j].record_type)
1512     {
1513     case GNUNET_DNSPARSER_TYPE_A:
1514       {
1515         struct sockaddr_in v4;
1516
1517         if (sizeof(struct in_addr) != rd[j].data_size)
1518         {
1519           GNUNET_break_op (0);
1520           continue;
1521         }
1522         memset (&v4,
1523                 0,
1524                 sizeof(v4));
1525         v4.sin_family = AF_INET;
1526         v4.sin_port = htons (53);
1527 #if HAVE_SOCKADDR_IN_SIN_LEN
1528         v4.sin_len = (u_char) sizeof(v4);
1529 #endif
1530         GNUNET_memcpy (&v4.sin_addr,
1531                        rd[j].data,
1532                        sizeof(struct in_addr));
1533         if (GNUNET_OK ==
1534             GNUNET_DNSSTUB_add_dns_sa (
1535               ac->authority_info.dns_authority.dns_handle,
1536               (const struct sockaddr *) &v4))
1537           ac->authority_info.dns_authority.found = GNUNET_YES;
1538         break;
1539       }
1540
1541     case GNUNET_DNSPARSER_TYPE_AAAA:
1542       {
1543         struct sockaddr_in6 v6;
1544
1545         if (sizeof(struct in6_addr) != rd[j].data_size)
1546         {
1547           GNUNET_break_op (0);
1548           continue;
1549         }
1550         /* FIXME: might want to check if we support IPv6 here,
1551            and otherwise skip this one and hope we find another */
1552         memset (&v6,
1553                 0,
1554                 sizeof(v6));
1555         v6.sin6_family = AF_INET6;
1556         v6.sin6_port = htons (53);
1557 #if HAVE_SOCKADDR_IN_SIN_LEN
1558         v6.sin6_len = (u_char) sizeof(v6);
1559 #endif
1560         GNUNET_memcpy (&v6.sin6_addr,
1561                        rd[j].data,
1562                        sizeof(struct in6_addr));
1563         if (GNUNET_OK ==
1564             GNUNET_DNSSTUB_add_dns_sa (
1565               ac->authority_info.dns_authority.dns_handle,
1566               (const struct sockaddr *) &v6))
1567           ac->authority_info.dns_authority.found = GNUNET_YES;
1568         break;
1569       }
1570
1571     default:
1572       break;
1573     }
1574   }
1575   continue_with_gns2dns (ac);
1576 }
1577
1578
1579 /**
1580  * Function called by the resolver for each address obtained from DNS.
1581  *
1582  * @param cls closure, a `struct Gns2DnsPending *`
1583  * @param addr one of the addresses of the host, NULL for the last address
1584  * @param addrlen length of @a addr
1585  */
1586 static void
1587 handle_gns2dns_ip (void *cls,
1588                    const struct sockaddr *addr,
1589                    socklen_t addrlen)
1590 {
1591   struct Gns2DnsPending *gp = cls;
1592   struct AuthorityChain *ac = gp->ac;
1593   struct sockaddr_storage ss;
1594   struct sockaddr_in *v4;
1595   struct sockaddr_in6 *v6;
1596
1597   if (NULL == addr)
1598   {
1599     /* DNS resolution finished */
1600     if (0 == gp->num_results)
1601       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1602                   "Failed to use DNS to resolve name of DNS resolver\n");
1603     GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1604                                  ac->authority_info.dns_authority.gp_tail,
1605                                  gp);
1606     GNUNET_free (gp);
1607     continue_with_gns2dns (ac);
1608     return;
1609   }
1610   GNUNET_memcpy (&ss,
1611                  addr,
1612                  addrlen);
1613   switch (ss.ss_family)
1614   {
1615   case AF_INET:
1616     v4 = (struct sockaddr_in *) &ss;
1617     v4->sin_port = htons (53);
1618     gp->num_results++;
1619     break;
1620
1621   case AF_INET6:
1622     v6 = (struct sockaddr_in6 *) &ss;
1623     v6->sin6_port = htons (53);
1624     gp->num_results++;
1625     break;
1626
1627   default:
1628     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1629                 "Unsupported AF %d\n",
1630                 ss.ss_family);
1631     return;
1632   }
1633   if (GNUNET_OK ==
1634       GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1635                                  (struct sockaddr *) &ss))
1636     ac->authority_info.dns_authority.found = GNUNET_YES;
1637 }
1638
1639
1640 /**
1641  * We found a CNAME record, perform recursive resolution on it.
1642  *
1643  * @param rh resolution handle
1644  * @param rd record with CNAME to resolve recursively
1645  */
1646 static void
1647 recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1648                             const struct GNUNET_GNSRECORD_Data *rd)
1649 {
1650   char *cname;
1651   size_t off;
1652
1653   off = 0;
1654   cname = GNUNET_DNSPARSER_parse_name (rd->data,
1655                                        rd->data_size,
1656                                        &off);
1657   if ((NULL == cname) ||
1658       (off != rd->data_size))
1659   {
1660     GNUNET_break_op (0);  /* record not well-formed */
1661     GNUNET_free_non_null (cname);
1662     fail_resolution (rh);
1663     return;
1664   }
1665   handle_gns_cname_result (rh,
1666                            cname);
1667   GNUNET_free (cname);
1668 }
1669
1670
1671 /**
1672  * We found a PKEY record, perform recursive resolution on it.
1673  *
1674  * @param rh resolution handle
1675  * @param rd record with PKEY to resolve recursively
1676  */
1677 static void
1678 recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1679                            const struct GNUNET_GNSRECORD_Data *rd)
1680 {
1681   struct AuthorityChain *ac;
1682
1683   /* delegation to another zone */
1684   if (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1685       rd->data_size)
1686   {
1687     GNUNET_break_op (0);
1688     fail_resolution (rh);
1689     return;
1690   }
1691   /* expand authority chain */
1692   ac = GNUNET_new (struct AuthorityChain);
1693   ac->rh = rh;
1694   ac->gns_authority = GNUNET_YES;
1695   GNUNET_memcpy (&ac->authority_info.gns_authority,
1696                  rd->data,
1697                  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1698   ac->label = resolver_lookup_get_next_label (rh);
1699   /* add AC to tail */
1700   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1701                                     rh->ac_tail,
1702                                     ac);
1703   /* recurse */
1704   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1705                                           rh);
1706 }
1707
1708
1709 /**
1710  * We found one or more GNS2DNS records, perform recursive resolution on it.
1711  * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1712  * so this function still needs to check which ones are GNS2DNS).
1713  *
1714  * @param rh resolution handle
1715  * @param rd_count length of the @a rd array
1716  * @param rd record with PKEY to resolve recursively
1717  * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1718  */
1719 static int
1720 recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1721                               unsigned int rd_count,
1722                               const struct GNUNET_GNSRECORD_Data *rd)
1723 {
1724   struct AuthorityChain *ac;
1725   const char *tld;
1726   char *ns;
1727
1728   ns = NULL;
1729   /* expand authority chain */
1730   ac = GNUNET_new (struct AuthorityChain);
1731   ac->rh = rh;
1732   ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1733
1734   for (unsigned int i = 0; i < rd_count; i++)
1735   {
1736     char *ip;
1737     char *n;
1738     size_t off;
1739     struct Gns2DnsPending *gp;
1740     struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1741     struct sockaddr_in v4;
1742     struct sockaddr_in6 v6;
1743
1744     if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1745       continue;
1746     off = 0;
1747     n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1748                                      rd[i].data_size,
1749                                      &off);
1750     ip = GNUNET_strdup (&rd[i].data[off]);
1751     off += strlen (ip) + 1;
1752
1753     if ((NULL == n) ||
1754         (NULL == ip) ||
1755         (off != rd[i].data_size))
1756     {
1757       GNUNET_break_op (0);
1758       GNUNET_free_non_null (n);
1759       GNUNET_free_non_null (ip);
1760       continue;
1761     }
1762     /* resolve 'ip' to determine the IP(s) of the DNS
1763        resolver to use for lookup of 'ns' */
1764     if (NULL != ns)
1765     {
1766       if (0 != strcasecmp (ns,
1767                            n))
1768       {
1769         /* NS values must all be the same for all GNS2DNS records,
1770            anything else leads to insanity */
1771         GNUNET_break_op (0);
1772         GNUNET_free (n);
1773         GNUNET_free (ip);
1774         continue;
1775       }
1776       GNUNET_free (n);
1777     }
1778     else
1779     {
1780       ns = n;
1781     }
1782
1783     /* check if 'ip' is already an IPv4/IPv6 address */
1784     if ((1 == inet_pton (AF_INET,
1785                          ip,
1786                          &v4)) ||
1787         (1 == inet_pton (AF_INET6,
1788                          ip,
1789                          &v6)))
1790     {
1791       GNUNET_break (GNUNET_OK ==
1792                     GNUNET_DNSSTUB_add_dns_ip (
1793                       ac->authority_info.dns_authority.dns_handle,
1794                       ip));
1795       ac->authority_info.dns_authority.found = GNUNET_YES;
1796       GNUNET_free (ip);
1797       continue;
1798     }
1799     tld = GNS_get_tld (ip);
1800     if ((0 != strcmp (tld, "+")) &&
1801         (GNUNET_OK != GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone)))
1802     {
1803       /* 'ip' is a DNS name */
1804       gp = GNUNET_new (struct Gns2DnsPending);
1805       gp->ac = ac;
1806       GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1807                                    ac->authority_info.dns_authority.gp_tail,
1808                                    gp);
1809       gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1810                                            AF_UNSPEC,
1811                                            GNUNET_TIME_UNIT_FOREVER_REL,
1812                                            &handle_gns2dns_ip,
1813                                            gp);
1814       GNUNET_free (ip);
1815       continue;
1816     }
1817     /* 'ip' should be a GNS name */
1818     gp = GNUNET_new (struct Gns2DnsPending);
1819     gp->ac = ac;
1820     GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1821                                  ac->authority_info.dns_authority.gp_tail,
1822                                  gp);
1823     gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1824     if (0 == strcmp (tld, "+"))
1825     {
1826       ip = translate_dot_plus (rh,
1827                                ip);
1828       tld = GNS_get_tld (ip);
1829       if (GNUNET_OK !=
1830           GNUNET_GNSRECORD_zkey_to_pkey (tld,
1831                                          &zone))
1832       {
1833         GNUNET_break_op (0);
1834         GNUNET_free (ip);
1835         continue;
1836       }
1837     }
1838     gp->rh->authority_zone = zone;
1839     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840                 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1841                 ip,
1842                 ns);
1843     gp->rh->name = ip;
1844     gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1845     gp->rh->proc = &handle_gns2dns_result;
1846     gp->rh->proc_cls = gp;
1847     gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1848     gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1849     gp->rh->loop_limiter = rh->loop_limiter + 1;
1850     gp->rh->task_id
1851       = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1852                                   gp->rh);
1853   }   /* end 'for all records' */
1854
1855   if (NULL == ns)
1856   {
1857     /* not a single GNS2DNS record found */
1858     GNUNET_free (ac);
1859     return GNUNET_SYSERR;
1860   }
1861   GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1862   strcpy (ac->authority_info.dns_authority.name,
1863           ns);
1864   /* for DNS recursion, the label is the full DNS name,
1865      created from the remainder of the GNS name and the
1866      name in the NS record */
1867   GNUNET_asprintf (&ac->label,
1868                    "%.*s%s%s",
1869                    (int) rh->name_resolution_pos,
1870                    rh->name,
1871                    (0 != rh->name_resolution_pos) ? "." : "",
1872                    ns);
1873   GNUNET_free (ns);
1874
1875   {
1876     /* the GNS name is UTF-8 and may include multibyte chars.
1877      * We have to convert the combined name to a DNS-compatible IDNA.
1878      */
1879     char *tmp = ac->label;
1880
1881     if (IDNA_SUCCESS != idna_to_ascii_8z (tmp,
1882                                           &ac->label,
1883                                           IDNA_ALLOW_UNASSIGNED))
1884     {
1885       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1886                   _ ("Name `%s' cannot be converted to IDNA."),
1887                   tmp);
1888       return GNUNET_SYSERR;
1889     }
1890     GNUNET_free (tmp);
1891   }
1892
1893   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1894                                     rh->ac_tail,
1895                                     ac);
1896   if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1897   {
1898     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1899                 _ ("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1900                 ac->label);
1901     return GNUNET_SYSERR;
1902   }
1903   continue_with_gns2dns (ac);
1904   return GNUNET_OK;
1905 }
1906
1907
1908 /**
1909  * Process a records that were decrypted from a block.
1910  *
1911  * @param cls closure with the `struct GNS_ResolverHandle`
1912  * @param rd_count number of entries in @a rd array
1913  * @param rd array of records with data to store
1914  */
1915 static void
1916 handle_gns_resolution_result (void *cls,
1917                               unsigned int rd_count,
1918                               const struct GNUNET_GNSRECORD_Data *rd)
1919 {
1920   struct GNS_ResolverHandle *rh = cls;
1921   char *cname;
1922   struct VpnContext *vpn_ctx;
1923   const struct GNUNET_TUN_GnsVpnRecord *vpn;
1924   const char *vname;
1925   struct GNUNET_HashCode vhash;
1926   int af;
1927   char scratch[UINT16_MAX];
1928   size_t scratch_off;
1929   size_t scratch_start;
1930   size_t off;
1931   struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1932   unsigned int rd_off;
1933
1934   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1935               "Resolution succeeded for `%s' in zone %s, got %u records\n",
1936               rh->ac_tail->label,
1937               GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1938               rd_count);
1939   if (0 == rd_count)
1940   {
1941     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1942                 _ ("GNS lookup failed (zero records found for `%s')\n"),
1943                 rh->name);
1944     fail_resolution (rh);
1945     return;
1946   }
1947
1948   if (0 == rh->name_resolution_pos)
1949   {
1950     /* top-level match, are we done yet? */
1951     if ((rd_count > 0) &&
1952         (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1953         (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
1954     {
1955       off = 0;
1956       cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1957                                            rd[0].data_size,
1958                                            &off);
1959       if ((NULL == cname) ||
1960           (off != rd[0].data_size))
1961       {
1962         GNUNET_break_op (0);
1963         GNUNET_free_non_null (cname);
1964         fail_resolution (rh);
1965         return;
1966       }
1967       handle_gns_cname_result (rh,
1968                                cname);
1969       GNUNET_free (cname);
1970       return;
1971     }
1972     /* If A/AAAA was requested, but we got a VPN
1973        record, we convert it to A/AAAA using GNUnet VPN */
1974     if ((GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1975         (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type))
1976     {
1977       for (unsigned int i = 0; i < rd_count; i++)
1978       {
1979         switch (rd[i].record_type)
1980         {
1981         case GNUNET_GNSRECORD_TYPE_VPN:
1982           {
1983             af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET :
1984                  AF_INET6;
1985             if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
1986                 rd[i].data_size)
1987             {
1988               GNUNET_break_op (0);
1989               fail_resolution (rh);
1990               return;
1991             }
1992             vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
1993             vname = (const char *) &vpn[1];
1994             if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
1995                                                            GNUNET_TUN_GnsVpnRecord)
1996                 ])
1997             {
1998               GNUNET_break_op (0);
1999               fail_resolution (rh);
2000               return;
2001             }
2002             GNUNET_TUN_service_name_to_hash (vname,
2003                                              &vhash);
2004             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2005                         "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
2006                         GNUNET_i2s (&vpn->peer),
2007                         vname,
2008                         (int) af,
2009                         (int) ntohs (vpn->proto));
2010             vpn_ctx = GNUNET_new (struct VpnContext);
2011             rh->vpn_ctx = vpn_ctx;
2012             vpn_ctx->rh = rh;
2013             vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
2014                                                                        rd);
2015             if (vpn_ctx->rd_data_size < 0)
2016             {
2017               GNUNET_break_op (0);
2018               GNUNET_free (vpn_ctx);
2019               fail_resolution (rh);
2020               return;
2021             }
2022             vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
2023             vpn_ctx->rd_count = rd_count;
2024             GNUNET_assert (vpn_ctx->rd_data_size ==
2025                            GNUNET_GNSRECORD_records_serialize (rd_count,
2026                                                                rd,
2027                                                                (size_t) vpn_ctx
2028                                                                ->rd_data_size,
2029                                                                vpn_ctx->rd_data));
2030             vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
2031                                                                 af,
2032                                                                 ntohs (
2033                                                                   vpn->proto),
2034                                                                 &vpn->peer,
2035                                                                 &vhash,
2036                                                                 GNUNET_TIME_relative_to_absolute (
2037                                                                   VPN_TIMEOUT),
2038                                                                 &
2039                                                                 vpn_allocation_cb,
2040                                                                 vpn_ctx);
2041             return;
2042           }
2043
2044         case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2045           {
2046             /* delegation to DNS */
2047             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2048                         "Found GNS2DNS record, delegating to DNS!\n");
2049             if (GNUNET_OK ==
2050                 recursive_gns2dns_resolution (rh,
2051                                               rd_count,
2052                                               rd))
2053               return;
2054             else
2055               goto fail;
2056           }
2057
2058         default:
2059           break;
2060         }         /* end: switch */
2061       }       /* end: for rd */
2062     }     /* end: name_resolution_pos */
2063     /* convert relative names in record values to absolute names,
2064        using 'scratch' array for memory allocations */
2065     scratch_off = 0;
2066     rd_off = 0;
2067     for (unsigned int i = 0; i < rd_count; i++)
2068     {
2069       GNUNET_assert (rd_off <= i);
2070       if ((0 != rh->protocol) &&
2071           (0 != rh->service) &&
2072           (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type))
2073         continue;     /* we _only_ care about boxed records */
2074
2075       GNUNET_assert (rd_off < rd_count);
2076       rd_new[rd_off] = rd[i];
2077       /* Check if the embedded name(s) end in "+", and if so,
2078          replace the "+" with the zone at "ac_tail", changing the name
2079          to a ".ZONEKEY".  The name is allocated on the 'scratch' array,
2080          so we can free it afterwards. */
2081       switch (rd[i].record_type)
2082       {
2083       case GNUNET_DNSPARSER_TYPE_CNAME:
2084         {
2085           char *cname;
2086
2087           off = 0;
2088           cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2089                                                rd[i].data_size,
2090                                                &off);
2091           if ((NULL == cname) ||
2092               (off != rd[i].data_size))
2093           {
2094             GNUNET_break_op (0);      /* record not well-formed */
2095           }
2096           else
2097           {
2098             cname = translate_dot_plus (rh, cname);
2099             GNUNET_break (NULL != cname);
2100             scratch_start = scratch_off;
2101             if (GNUNET_OK !=
2102                 GNUNET_DNSPARSER_builder_add_name (scratch,
2103                                                    sizeof(scratch),
2104                                                    &scratch_off,
2105                                                    cname))
2106             {
2107               GNUNET_break (0);
2108             }
2109             else
2110             {
2111               GNUNET_assert (rd_off < rd_count);
2112               rd_new[rd_off].data = &scratch[scratch_start];
2113               rd_new[rd_off].data_size = scratch_off - scratch_start;
2114               rd_off++;
2115             }
2116           }
2117           GNUNET_free_non_null (cname);
2118         }
2119         break;
2120
2121       case GNUNET_DNSPARSER_TYPE_SOA:
2122         {
2123           struct GNUNET_DNSPARSER_SoaRecord *soa;
2124
2125           off = 0;
2126           soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2127                                             rd[i].data_size,
2128                                             &off);
2129           if ((NULL == soa) ||
2130               (off != rd[i].data_size))
2131           {
2132             GNUNET_break_op (0);      /* record not well-formed */
2133           }
2134           else
2135           {
2136             soa->mname = translate_dot_plus (rh, soa->mname);
2137             soa->rname = translate_dot_plus (rh, soa->rname);
2138             scratch_start = scratch_off;
2139             if (GNUNET_OK !=
2140                 GNUNET_DNSPARSER_builder_add_soa (scratch,
2141                                                   sizeof(scratch),
2142                                                   &scratch_off,
2143                                                   soa))
2144             {
2145               GNUNET_break (0);
2146             }
2147             else
2148             {
2149               GNUNET_assert (rd_off < rd_count);
2150               rd_new[rd_off].data = &scratch[scratch_start];
2151               rd_new[rd_off].data_size = scratch_off - scratch_start;
2152               rd_off++;
2153             }
2154           }
2155           if (NULL != soa)
2156             GNUNET_DNSPARSER_free_soa (soa);
2157         }
2158         break;
2159
2160       case GNUNET_DNSPARSER_TYPE_MX:
2161         {
2162           struct GNUNET_DNSPARSER_MxRecord *mx;
2163
2164           off = 0;
2165           mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2166                                           rd[i].data_size,
2167                                           &off);
2168           if ((NULL == mx) ||
2169               (off != rd[i].data_size))
2170           {
2171             GNUNET_break_op (0);      /* record not well-formed */
2172           }
2173           else
2174           {
2175             mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2176             scratch_start = scratch_off;
2177             if (GNUNET_OK !=
2178                 GNUNET_DNSPARSER_builder_add_mx (scratch,
2179                                                  sizeof(scratch),
2180                                                  &scratch_off,
2181                                                  mx))
2182             {
2183               GNUNET_break (0);
2184             }
2185             else
2186             {
2187               GNUNET_assert (rd_off < rd_count);
2188               rd_new[rd_off].data = &scratch[scratch_start];
2189               rd_new[rd_off].data_size = scratch_off - scratch_start;
2190               rd_off++;
2191             }
2192           }
2193           if (NULL != mx)
2194             GNUNET_DNSPARSER_free_mx (mx);
2195         }
2196         break;
2197
2198       case GNUNET_DNSPARSER_TYPE_SRV:
2199         {
2200           struct GNUNET_DNSPARSER_SrvRecord *srv;
2201
2202           off = 0;
2203           srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2204                                             rd[i].data_size,
2205                                             &off);
2206           if ((NULL == srv) ||
2207               (off != rd[i].data_size))
2208           {
2209             GNUNET_break_op (0);      /* record not well-formed */
2210           }
2211           else
2212           {
2213             srv->target = translate_dot_plus (rh, srv->target);
2214             scratch_start = scratch_off;
2215             if (GNUNET_OK !=
2216                 GNUNET_DNSPARSER_builder_add_srv (scratch,
2217                                                   sizeof(scratch),
2218                                                   &scratch_off,
2219                                                   srv))
2220             {
2221               GNUNET_break (0);
2222             }
2223             else
2224             {
2225               GNUNET_assert (rd_off < rd_count);
2226               rd_new[rd_off].data = &scratch[scratch_start];
2227               rd_new[rd_off].data_size = scratch_off - scratch_start;
2228               rd_off++;
2229             }
2230           }
2231           if (NULL != srv)
2232             GNUNET_DNSPARSER_free_srv (srv);
2233         }
2234         break;
2235
2236       case GNUNET_GNSRECORD_TYPE_NICK:
2237         /* ignore */
2238         break;
2239
2240       case GNUNET_GNSRECORD_TYPE_PKEY:
2241         {
2242           struct GNUNET_CRYPTO_EcdsaPublicKey pub;
2243
2244           if (rd[i].data_size != sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))
2245           {
2246             GNUNET_break_op (0);
2247             break;
2248           }
2249           GNUNET_memcpy (&pub,
2250                          rd[i].data,
2251                          rd[i].data_size);
2252           rd_off++;
2253           if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
2254           {
2255             /* try to resolve "@" */
2256             struct AuthorityChain *ac;
2257
2258             ac = GNUNET_new (struct AuthorityChain);
2259             ac->rh = rh;
2260             ac->gns_authority = GNUNET_YES;
2261             ac->authority_info.gns_authority = pub;
2262             ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2263             GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2264                                               rh->ac_tail,
2265                                               ac);
2266             rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2267                                                     rh);
2268             return;
2269           }
2270         }
2271         break;
2272
2273       case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2274         {
2275           /* delegation to DNS */
2276           if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2277           {
2278             rd_off++;
2279             break;       /* do not follow to DNS, we wanted the GNS2DNS record! */
2280           }
2281           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2282                       "Found GNS2DNS record, delegating to DNS!\n");
2283           if (GNUNET_OK ==
2284               recursive_gns2dns_resolution (rh,
2285                                             rd_count,
2286                                             rd))
2287             return;
2288           else
2289             goto fail;
2290         }
2291
2292       case GNUNET_GNSRECORD_TYPE_BOX:
2293         {
2294           /* unbox SRV/TLSA records if a specific one was requested */
2295           if ((0 != rh->protocol) &&
2296               (0 != rh->service) &&
2297               (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_BoxRecord)))
2298           {
2299             const struct GNUNET_GNSRECORD_BoxRecord *box;
2300
2301             box = rd[i].data;
2302             if ((ntohs (box->protocol) == rh->protocol) &&
2303                 (ntohs (box->service) == rh->service))
2304             {
2305               /* Box matches, unbox! */
2306               GNUNET_assert (rd_off < rd_count);
2307               rd_new[rd_off].record_type = ntohl (box->record_type);
2308               rd_new[rd_off].data_size -= sizeof(struct
2309                                                  GNUNET_GNSRECORD_BoxRecord);
2310               rd_new[rd_off].data = &box[1];
2311               rd_off++;
2312             }
2313           }
2314           else
2315           {
2316             /* no specific protocol/service specified, preserve all BOX
2317                records (for modern, GNS-enabled applications) */
2318             rd_off++;
2319           }
2320           break;
2321         }
2322
2323       default:
2324         rd_off++;
2325         break;
2326       }       /* end: switch */
2327     }     /* end: for rd_count */
2328
2329     /* yes, we are done, return result */
2330     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331                 "Returning GNS response for `%s' with %u answers\n",
2332                 rh->ac_tail->label,
2333                 rd_off);
2334     rh->proc (rh->proc_cls,
2335               rd_off,
2336               rd_new);
2337     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2338                                             rh);
2339     return;
2340   }
2341
2342   switch (rd[0].record_type)
2343   {
2344   case GNUNET_DNSPARSER_TYPE_CNAME:
2345     GNUNET_break_op (1 == rd_count);  /* CNAME should be unique */
2346     recursive_cname_resolution (rh,
2347                                 &rd[0]);
2348     return;
2349
2350   case GNUNET_GNSRECORD_TYPE_PKEY:
2351     GNUNET_break_op (1 == rd_count);  /* PKEY should be unique */
2352     recursive_pkey_resolution (rh,
2353                                &rd[0]);
2354     return;
2355
2356   default:
2357     if (GNUNET_OK ==
2358         recursive_gns2dns_resolution (rh,
2359                                       rd_count,
2360                                       rd))
2361       return;
2362     break;
2363   }
2364 fail:
2365   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2366               _ ("GNS lookup recursion failed (no delegation record found)\n"));
2367   fail_resolution (rh);
2368 }
2369
2370
2371 /**
2372  * Function called once the namestore has completed the request for
2373  * caching a block.
2374  *
2375  * @param cls closure with the `struct CacheOps`
2376  * @param success #GNUNET_OK on success
2377  * @param emsg error message
2378  */
2379 static void
2380 namecache_cache_continuation (void *cls,
2381                               int32_t success,
2382                               const char *emsg)
2383 {
2384   struct CacheOps *co = cls;
2385
2386   co->namecache_qe_cache = NULL;
2387   if (GNUNET_OK != success)
2388     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2389                 _ ("Failed to cache GNS resolution: %s\n"),
2390                 emsg);
2391   GNUNET_CONTAINER_DLL_remove (co_head,
2392                                co_tail,
2393                                co);
2394   GNUNET_free (co);
2395 }
2396
2397
2398 /**
2399  * Iterator called on each result obtained for a DHT
2400  * operation that expects a reply
2401  *
2402  * @param cls closure with the `struct GNS_ResolverHandle`
2403  * @param exp when will this value expire
2404  * @param key key of the result
2405  * @param get_path peers on reply path (or NULL if not recorded)
2406  *                 [0] = datastore's first neighbor, [length - 1] = local peer
2407  * @param get_path_length number of entries in @a get_path
2408  * @param put_path peers on the PUT path (or NULL if not recorded)
2409  *                 [0] = origin, [length - 1] = datastore
2410  * @param put_path_length number of entries in @a put_path
2411  * @param type type of the result
2412  * @param size number of bytes in data
2413  * @param data pointer to the result data
2414  */
2415 static void
2416 handle_dht_response (void *cls,
2417                      struct GNUNET_TIME_Absolute exp,
2418                      const struct GNUNET_HashCode *key,
2419                      const struct GNUNET_PeerIdentity *get_path,
2420                      unsigned int get_path_length,
2421                      const struct GNUNET_PeerIdentity *put_path,
2422                      unsigned int put_path_length,
2423                      enum GNUNET_BLOCK_Type type,
2424                      size_t size,
2425                      const void *data)
2426 {
2427   struct GNS_ResolverHandle *rh = cls;
2428   struct AuthorityChain *ac = rh->ac_tail;
2429   const struct GNUNET_GNSRECORD_Block *block;
2430   struct CacheOps *co;
2431
2432   (void) exp;
2433   (void) key;
2434   (void) get_path;
2435   (void) get_path_length;
2436   (void) put_path;
2437   (void) put_path_length;
2438   (void) type;
2439   GNUNET_DHT_get_stop (rh->get_handle);
2440   rh->get_handle = NULL;
2441   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2442   rh->dht_heap_node = NULL;
2443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444               "Handling response from the DHT\n");
2445   if (size < sizeof(struct GNUNET_GNSRECORD_Block))
2446   {
2447     /* how did this pass DHT block validation!? */
2448     GNUNET_break (0);
2449     fail_resolution (rh);
2450     return;
2451   }
2452   block = data;
2453   if (size !=
2454       ntohl (block->purpose.size)
2455       + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
2456       + sizeof(struct GNUNET_CRYPTO_EcdsaSignature))
2457   {
2458     /* how did this pass DHT block validation!? */
2459     GNUNET_break (0);
2460     fail_resolution (rh);
2461     return;
2462   }
2463   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2464               "Decrypting DHT block of size %u for `%s', expires %s\n",
2465               ntohl (block->purpose.size),
2466               rh->name,
2467               GNUNET_STRINGS_absolute_time_to_string (exp));
2468   if (GNUNET_OK !=
2469       GNUNET_GNSRECORD_block_decrypt (block,
2470                                       &ac->authority_info.gns_authority,
2471                                       ac->label,
2472                                       &handle_gns_resolution_result,
2473                                       rh))
2474   {
2475     GNUNET_break_op (0);  /* block was ill-formed */
2476     fail_resolution (rh);
2477     return;
2478   }
2479   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
2480                                                  block->expiration_time)).
2481       rel_value_us)
2482   {
2483     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484                 "Received expired block from the DHT, will not cache it.\n");
2485     return;
2486   }
2487   if (GNUNET_YES == disable_cache)
2488     return;
2489   /* Cache well-formed blocks */
2490   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2491               "Caching response from the DHT in namecache\n");
2492   co = GNUNET_new (struct CacheOps);
2493   co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2494                                                          block,
2495                                                          &
2496                                                          namecache_cache_continuation,
2497                                                          co);
2498   GNUNET_CONTAINER_DLL_insert (co_head,
2499                                co_tail,
2500                                co);
2501 }
2502
2503
2504 /**
2505  * Initiate a DHT query for a set of GNS records.
2506  *
2507  * @param rh resolution handle
2508  * @param query key to use in the DHT lookup
2509  */
2510 static void
2511 start_dht_request (struct GNS_ResolverHandle *rh,
2512                    const struct GNUNET_HashCode *query)
2513 {
2514   struct GNS_ResolverHandle *rx;
2515
2516   GNUNET_assert (NULL == rh->get_handle);
2517   rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2518                                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2519                                          query,
2520                                          DHT_GNS_REPLICATION_LEVEL,
2521                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2522                                          NULL, 0,
2523                                          &handle_dht_response, rh);
2524   rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2525                                                     rh,
2526                                                     GNUNET_TIME_absolute_get ().
2527                                                     abs_value_us);
2528   if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) >
2529       max_allowed_background_queries)
2530   {
2531     /* fail longest-standing DHT request */
2532     rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2533     rx->dht_heap_node = NULL;
2534     GNUNET_assert (NULL != rx);
2535     fail_resolution (rx);
2536   }
2537 }
2538
2539
2540 /**
2541  * Process a records that were decrypted from a block that we got from
2542  * the namecache.  Simply calls #handle_gns_resolution_result().
2543  *
2544  * @param cls closure with the `struct GNS_ResolverHandle`
2545  * @param rd_count number of entries in @a rd array
2546  * @param rd array of records with data to store
2547  */
2548 static void
2549 handle_gns_namecache_resolution_result (void *cls,
2550                                         unsigned int rd_count,
2551                                         const struct GNUNET_GNSRECORD_Data *rd)
2552 {
2553   struct GNS_ResolverHandle *rh = cls;
2554
2555   if (0 == rd_count)
2556     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2557                 _ ("GNS namecache returned empty result for `%s'\n"),
2558                 rh->name);
2559   handle_gns_resolution_result (rh,
2560                                 rd_count,
2561                                 rd);
2562 }
2563
2564
2565 /**
2566  * Process a record that was stored in the namecache.
2567  *
2568  * @param cls closure with the `struct GNS_ResolverHandle`
2569  * @param block block that was stored in the namecache
2570  */
2571 static void
2572 handle_namecache_block_response (void *cls,
2573                                  const struct GNUNET_GNSRECORD_Block *block)
2574 {
2575   struct GNS_ResolverHandle *rh = cls;
2576   struct AuthorityChain *ac = rh->ac_tail;
2577   const char *label = ac->label;
2578   const struct GNUNET_CRYPTO_EcdsaPublicKey *auth =
2579     &ac->authority_info.gns_authority;
2580   struct GNUNET_HashCode query;
2581
2582   GNUNET_assert (NULL != rh->namecache_qe);
2583   rh->namecache_qe = NULL;
2584   if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
2585        ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2586         (ac != rh->ac_head))) &&
2587       ((NULL == block) ||
2588        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
2589                                                    block->expiration_time)).
2590         rel_value_us)))
2591   {
2592     /* namecache knows nothing; try DHT lookup */
2593     GNUNET_GNSRECORD_query_from_public_key (auth,
2594                                             label,
2595                                             &query);
2596     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2597                 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2598                 ac->label,
2599                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2600                 GNUNET_h2s (&query));
2601     start_dht_request (rh, &query);
2602     return;
2603   }
2604
2605   if ((NULL == block) ||
2606       (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
2607                                                   block->expiration_time)).
2608        rel_value_us))
2609   {
2610     /* DHT not permitted and no local result, fail */
2611     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2612                 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2613                 ac->label,
2614                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2615     fail_resolution (rh);
2616     return;
2617   }
2618   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2619               "Received result from namecache for label `%s'\n",
2620               ac->label);
2621
2622   if (GNUNET_OK !=
2623       GNUNET_GNSRECORD_block_decrypt (block,
2624                                       auth,
2625                                       label,
2626                                       &handle_gns_namecache_resolution_result,
2627                                       rh))
2628   {
2629     GNUNET_break_op (0);  /* block was ill-formed */
2630     /* try DHT instead */
2631     GNUNET_GNSRECORD_query_from_public_key (auth,
2632                                             label,
2633                                             &query);
2634     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2635                 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2636                 ac->label,
2637                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2638                 GNUNET_h2s (&query));
2639     start_dht_request (rh, &query);
2640     return;
2641   }
2642 }
2643
2644
2645 /**
2646  * Lookup tail of our authority chain in the namecache.
2647  *
2648  * @param rh query we are processing
2649  */
2650 static void
2651 recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2652 {
2653   struct AuthorityChain *ac = rh->ac_tail;
2654   struct GNUNET_HashCode query;
2655
2656   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2657               "Starting GNS resolution for `%s' in zone %s\n",
2658               ac->label,
2659               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2660   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2661                                           ac->label,
2662                                           &query);
2663   if (GNUNET_YES != disable_cache)
2664   {
2665     rh->namecache_qe
2666       = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2667                                        &query,
2668                                        &handle_namecache_block_response,
2669                                        rh);
2670     GNUNET_assert (NULL != rh->namecache_qe);
2671   }
2672   else
2673   {
2674     start_dht_request (rh,
2675                        &query);
2676   }
2677 }
2678
2679
2680 /**
2681  * Function called with the result from a revocation check.
2682  *
2683  * @param cls the `struct GNS_ResovlerHandle`
2684  * @param is_valid #GNUNET_YES if the zone was not yet revoked
2685  */
2686 static void
2687 handle_revocation_result (void *cls,
2688                           int is_valid)
2689 {
2690   struct GNS_ResolverHandle *rh = cls;
2691   struct AuthorityChain *ac = rh->ac_tail;
2692
2693   rh->rev_check = NULL;
2694   if (GNUNET_YES != is_valid)
2695   {
2696     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2697                 _ ("Zone %s was revoked, resolution fails\n"),
2698                 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2699     fail_resolution (rh);
2700     return;
2701   }
2702   recursive_gns_resolution_namecache (rh);
2703 }
2704
2705
2706 /**
2707  * Perform revocation check on tail of our authority chain.
2708  *
2709  * @param rh query we are processing
2710  */
2711 static void
2712 recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2713 {
2714   struct AuthorityChain *ac = rh->ac_tail;
2715
2716   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2717               "Starting revocation check for zone %s\n",
2718               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2719   rh->rev_check = GNUNET_REVOCATION_query (cfg,
2720                                            &ac->authority_info.gns_authority,
2721                                            &handle_revocation_result,
2722                                            rh);
2723   GNUNET_assert (NULL != rh->rev_check);
2724 }
2725
2726
2727 /**
2728  * Task scheduled to continue with the resolution process.
2729  *
2730  * @param cls the `struct GNS_ResolverHandle` of the resolution
2731  */
2732 static void
2733 recursive_resolution (void *cls)
2734 {
2735   struct GNS_ResolverHandle *rh = cls;
2736
2737   rh->task_id = NULL;
2738   if (MAX_RECURSION < rh->loop_limiter++)
2739   {
2740     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2741                 "Encountered unbounded recursion resolving `%s'\n",
2742                 rh->name);
2743     fail_resolution (rh);
2744     return;
2745   }
2746   if (GNUNET_YES == rh->ac_tail->gns_authority)
2747     recursive_gns_resolution_revocation (rh);
2748   else
2749     recursive_dns_resolution (rh);
2750 }
2751
2752
2753 /**
2754  * Begin the resolution process from 'name', starting with
2755  * the identification of the zone specified by 'name'.
2756  *
2757  * @param cls the `struct GNS_ResolverHandle`
2758  */
2759 static void
2760 start_resolver_lookup (void *cls)
2761 {
2762   struct GNS_ResolverHandle *rh = cls;
2763   struct AuthorityChain *ac;
2764   struct in_addr v4;
2765   struct in6_addr v6;
2766
2767   rh->task_id = NULL;
2768   if (1 == inet_pton (AF_INET,
2769                       rh->name,
2770                       &v4))
2771   {
2772     /* name is IPv4 address, pretend it's an A record */
2773     struct GNUNET_GNSRECORD_Data rd;
2774
2775     rd.data = &v4;
2776     rd.data_size = sizeof(v4);
2777     rd.expiration_time = UINT64_MAX;
2778     rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2779     rd.flags = 0;
2780     rh->proc (rh->proc_cls,
2781               1,
2782               &rd);
2783     GNUNET_assert (NULL == rh->task_id);
2784     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2785                                             rh);
2786     return;
2787   }
2788   if (1 == inet_pton (AF_INET6,
2789                       rh->name,
2790                       &v6))
2791   {
2792     /* name is IPv6 address, pretend it's an AAAA record */
2793     struct GNUNET_GNSRECORD_Data rd;
2794
2795     rd.data = &v6;
2796     rd.data_size = sizeof(v6);
2797     rd.expiration_time = UINT64_MAX;
2798     rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2799     rd.flags = 0;
2800     rh->proc (rh->proc_cls,
2801               1,
2802               &rd);
2803     GNUNET_assert (NULL == rh->task_id);
2804     rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2805                                             rh);
2806     return;
2807   }
2808
2809   ac = GNUNET_new (struct AuthorityChain);
2810   ac->rh = rh;
2811   ac->label = resolver_lookup_get_next_label (rh);
2812   if (NULL == ac->label)
2813     /* name was just the "TLD", so we default to label
2814      #GNUNET_GNS_EMPTY_LABEL_AT */
2815     ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2816   ac->gns_authority = GNUNET_YES;
2817   ac->authority_info.gns_authority = rh->authority_zone;
2818   GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2819                                     rh->ac_tail,
2820                                     ac);
2821   rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2822                                           rh);
2823 }
2824
2825
2826 /**
2827  * Lookup of a record in a specific zone calls lookup result processor
2828  * on result.
2829  *
2830  * @param zone the zone to perform the lookup in
2831  * @param record_type the record type to look up
2832  * @param name the name to look up
2833  * @param options local options to control local lookup
2834  * @param proc the processor to call on result
2835  * @param proc_cls the closure to pass to @a proc
2836  * @return handle to cancel operation
2837  */
2838 struct GNS_ResolverHandle *
2839 GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2840                      uint32_t record_type,
2841                      const char *name,
2842                      enum GNUNET_GNS_LocalOptions options,
2843                      GNS_ResultProcessor proc,
2844                      void *proc_cls)
2845 {
2846   struct GNS_ResolverHandle *rh;
2847
2848   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2849               "Starting lookup for `%s'\n",
2850               name);
2851   rh = GNUNET_new (struct GNS_ResolverHandle);
2852   GNUNET_CONTAINER_DLL_insert (rlh_head,
2853                                rlh_tail,
2854                                rh);
2855   rh->authority_zone = *zone;
2856   rh->proc = proc;
2857   rh->proc_cls = proc_cls;
2858   rh->options = options;
2859   rh->record_type = record_type;
2860   rh->name = GNUNET_strdup (name);
2861   rh->name_resolution_pos = strlen (name);
2862   rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2863                                           rh);
2864   return rh;
2865 }
2866
2867
2868 /**
2869  * Cancel active resolution (i.e. client disconnected).
2870  *
2871  * @param rh resolution to abort
2872  */
2873 void
2874 GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2875 {
2876   struct DnsResult *dr;
2877   struct AuthorityChain *ac;
2878   struct VpnContext *vpn_ctx;
2879
2880   GNUNET_CONTAINER_DLL_remove (rlh_head,
2881                                rlh_tail,
2882                                rh);
2883   if (NULL != rh->dns_request)
2884   {
2885     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2886     rh->dns_request = NULL;
2887   }
2888   while (NULL != (ac = rh->ac_head))
2889   {
2890     GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2891                                  rh->ac_tail,
2892                                  ac);
2893     if (GNUNET_NO == ac->gns_authority)
2894     {
2895       struct Gns2DnsPending *gp;
2896
2897       while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2898       {
2899         GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2900                                      ac->authority_info.dns_authority.gp_tail,
2901                                      gp);
2902         if (NULL != gp->rh)
2903         {
2904           /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2905              using GNS_resolver_lookup_cancel here, we need to
2906              add it first... */
2907           GNUNET_CONTAINER_DLL_insert (rlh_head,
2908                                        rlh_tail,
2909                                        gp->rh);
2910           GNUNET_assert (NULL == gp->rh->task_id);
2911           gp->rh->task_id = GNUNET_SCHEDULER_add_now (
2912             &GNS_resolver_lookup_cancel_,
2913             gp->rh);
2914           gp->rh = NULL;
2915         }
2916         if (NULL != gp->dns_rh)
2917         {
2918           GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2919           gp->dns_rh = NULL;
2920         }
2921         GNUNET_free (gp);
2922       }
2923       GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2924     }
2925     GNUNET_free (ac->label);
2926     GNUNET_free (ac);
2927   }
2928   if (NULL != rh->task_id)
2929   {
2930     GNUNET_SCHEDULER_cancel (rh->task_id);
2931     rh->task_id = NULL;
2932   }
2933   if (NULL != rh->get_handle)
2934   {
2935     GNUNET_DHT_get_stop (rh->get_handle);
2936     rh->get_handle = NULL;
2937   }
2938   if (NULL != rh->dht_heap_node)
2939   {
2940     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2941     rh->dht_heap_node = NULL;
2942   }
2943   if (NULL != (vpn_ctx = rh->vpn_ctx))
2944   {
2945     GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
2946     GNUNET_free (vpn_ctx->rd_data);
2947     GNUNET_free (vpn_ctx);
2948   }
2949   if (NULL != rh->namecache_qe)
2950   {
2951     GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2952     rh->namecache_qe = NULL;
2953   }
2954   if (NULL != rh->rev_check)
2955   {
2956     GNUNET_REVOCATION_query_cancel (rh->rev_check);
2957     rh->rev_check = NULL;
2958   }
2959   if (NULL != rh->std_resolve)
2960   {
2961     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2962                 "Canceling standard DNS resolution\n");
2963     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2964     rh->std_resolve = NULL;
2965   }
2966   while (NULL != (dr = rh->dns_result_head))
2967   {
2968     GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2969                                  rh->dns_result_tail,
2970                                  dr);
2971     GNUNET_free (dr);
2972   }
2973   GNUNET_free_non_null (rh->leho);
2974   GNUNET_free (rh->name);
2975   GNUNET_free (rh);
2976 }
2977
2978
2979 /* ***************** Resolver initialization ********************* */
2980
2981
2982 /**
2983  * Initialize the resolver
2984  *
2985  * @param nc the namecache handle
2986  * @param dht the dht handle
2987  * @param c configuration handle
2988  * @param max_bg_queries maximum number of parallel background queries in dht
2989  */
2990 void
2991 GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2992                    struct GNUNET_DHT_Handle *dht,
2993                    const struct GNUNET_CONFIGURATION_Handle *c,
2994                    unsigned long long max_bg_queries)
2995 {
2996   cfg = c;
2997   namecache_handle = nc;
2998   dht_handle = dht;
2999   dht_lookup_heap =
3000     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3001   max_allowed_background_queries = max_bg_queries;
3002   disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3003                                                         "namecache",
3004                                                         "DISABLE");
3005   if (GNUNET_YES == disable_cache)
3006     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3007                 "Namecache disabled\n");
3008   vpn_handle = GNUNET_VPN_connect (cfg);
3009 }
3010
3011
3012 /**
3013  * Shutdown resolver
3014  */
3015 void
3016 GNS_resolver_done ()
3017 {
3018   struct GNS_ResolverHandle *rh;
3019   struct CacheOps *co;
3020
3021   /* abort active resolutions */
3022   while (NULL != (rh = rlh_head))
3023   {
3024     rh->proc (rh->proc_cls,
3025               0,
3026               NULL);
3027     GNS_resolver_lookup_cancel (rh);
3028   }
3029   while (NULL != (co = co_head))
3030   {
3031     GNUNET_CONTAINER_DLL_remove (co_head,
3032                                  co_tail,
3033                                  co);
3034     GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
3035     GNUNET_free (co);
3036   }
3037   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3038   dht_lookup_heap = NULL;
3039   GNUNET_VPN_disconnect (vpn_handle);
3040   vpn_handle = NULL;
3041   dht_handle = NULL;
3042   namecache_handle = NULL;
3043 }
3044
3045
3046 /* end of gnunet-service-gns_resolver.c */