+/**
+ * We've resolved the IP address for the DNS resolver to use
+ * after encountering a GNS2DNS record.
+ *
+ * TODO: Right now we only foward the request to ONE DNS resolver,
+ * even if we get multiple IP addresses back; a correct implementation
+ * should try all DNS resolvers.
+ *
+ * @param cls the `struct GNS_ResolverHandle` where we encountered
+ * the GNS2DNS record
+ * @param rd_count number of records in @a rd
+ * @param rd addresses for the DNS resolver (presumably)
+ */
+static void
+handle_gns2dns_result (void *cls,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct GNS_ResolverHandle *rh = cls;
+ struct AuthorityChain *ac;
+ unsigned int j;
+ struct sockaddr *sa;
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ size_t sa_len;
+
+ /* find suitable A/AAAA record */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u results for IP address of DNS server for GNS2DNS transition\n",
+ rd_count);
+ /* enable cleanup of 'rh' handle that comes next... */
+ GNUNET_CONTAINER_DLL_insert (rlh_head,
+ rlh_tail,
+ rh->g2dc->rh);
+ rh->g2dc->rh = NULL;
+ sa = NULL;
+ sa_len = 0;
+ for (j=0;j<rd_count;j++)
+ {
+ switch (rd[j].record_type)
+ {
+ case GNUNET_DNSPARSER_TYPE_A:
+ if (sizeof (struct in_addr) != rd[j].data_size)
+ {
+ GNUNET_break_op (0);
+ rh->proc (rh->proc_cls, 0, NULL);
+ GNS_resolver_lookup_cancel (rh);
+ return;
+ }
+ /* FIXME: might want to check if we support IPv4 here,
+ and otherwise skip this one and hope we find another */
+ memset (&v4, 0, sizeof (v4));
+ sa_len = sizeof (v4);
+ v4.sin_family = AF_INET;
+ v4.sin_port = htons (53);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v4.sin_len = (u_char) sa_len;
+#endif
+ memcpy (&v4.sin_addr,
+ rd[j].data,
+ sizeof (struct in_addr));
+ sa = (struct sockaddr *) &v4;
+ break;
+ case GNUNET_DNSPARSER_TYPE_AAAA:
+ if (sizeof (struct in6_addr) != rd[j].data_size)
+ {
+ GNUNET_break_op (0);
+ rh->proc (rh->proc_cls, 0, NULL);
+ GNS_resolver_lookup_cancel (rh);
+ return;
+ }
+ /* FIXME: might want to check if we support IPv6 here,
+ and otherwise skip this one and hope we find another */
+ memset (&v6, 0, sizeof (v6));
+ sa_len = sizeof (v6);
+ v6.sin6_family = AF_INET6;
+ v6.sin6_port = htons (53);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v6.sin6_len = (u_char) sa_len;
+#endif
+ memcpy (&v6.sin6_addr,
+ rd[j].data,
+ sizeof (struct in6_addr));
+ sa = (struct sockaddr *) &v6;
+ break;
+ default:
+ break;
+ }
+ if (NULL != sa)
+ break;
+ }
+ if (NULL == sa)
+ {
+ /* we cannot continue; NS without A/AAAA */
+ rh->proc (rh->proc_cls, 0, NULL);
+ GNS_resolver_lookup_cancel (rh);
+ return;
+ }
+ /* expand authority chain */
+ ac = GNUNET_new (struct AuthorityChain);
+ ac->rh = rh;
+ strcpy (ac->authority_info.dns_authority.name,
+ rh->g2dc->ns);
+ memcpy (&ac->authority_info.dns_authority.dns_ip,
+ sa,
+ sa_len);
+ /* for DNS recursion, the label is the full DNS name,
+ created from the remainder of the GNS name and the
+ name in the NS record */
+ GNUNET_asprintf (&ac->label,
+ "%.*s%s%s",
+ (int) rh->name_resolution_pos,
+ rh->name,
+ (0 != rh->name_resolution_pos) ? "." : "",
+ rh->g2dc->ns);
+ GNUNET_free (rh->g2dc->ns);
+ GNUNET_free (rh->g2dc);
+ rh->g2dc = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Will continue resolution using DNS server `%s' to resolve `%s'\n",
+ GNUNET_a2s (sa, sa_len),
+ ac->label);
+ GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
+ rh->ac_tail,
+ ac);
+ if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
+ ac->label);
+ rh->proc (rh->proc_cls, 0, NULL);
+ GNS_resolver_lookup_cancel (rh);
+ return;
+ }
+ /* recurse */
+ rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
+ rh);
+}
+
+