From: Christian Grothoff Date: Wed, 6 Nov 2013 20:30:18 +0000 (+0000) Subject: -improve testcase to actually test #3093 X-Git-Tag: initial-import-from-subversion-38251~6225 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=cc846ca686a7e2e894801b731630cfa50408b7e2;p=oweals%2Fgnunet.git -improve testcase to actually test #3093 --- diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c index c881b6b83..28ec58430 100644 --- a/src/gns/gnunet-service-gns_resolver.c +++ b/src/gns/gnunet-service-gns_resolver.c @@ -213,6 +213,30 @@ struct VpnContext }; +/** + * Information we keep during the resolution of an + * IP address for a DNS server while handling a + * GNS2DNS record. + */ +struct Gns2DnsContext +{ + + /** + * DNS domain in which the resolution will continue + * (first part of the GNS2DNS record). + */ + char *ns; + + /** + * Handle for the resolution of the IP part of the + * GNS2DNS record. Will return to us the addresses + * of the DNS resolver to use. + */ + struct GNS_ResolverHandle *rh; + +}; + + /** * Handle to a currenty pending resolution. On result (positive or * negative) the #GNS_ResultProcessor is called. @@ -241,10 +265,16 @@ struct GNS_ResolverHandle GNS_ResultProcessor proc; /** - * closure passed to proc + * closure passed to @e proc */ void* proc_cls; + /** + * Handle used during GNS2DNS resolution for looking up the + * IP address of the DNS server. + */ + struct Gns2DnsContext *g2dc; + /** * Handle for DHT lookups. should be NULL if no lookups are in progress */ @@ -1144,6 +1174,135 @@ vpn_allocation_cb (void *cls, } +/** + * 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 */ + rh->g2dc->rh = NULL; + sa = NULL; + sa_len = 0; + for (j=0;jproc (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_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); +} + + /** * Process a records that were decrypted from a block. * @@ -1159,11 +1318,6 @@ handle_gns_resolution_result (void *cls, struct GNS_ResolverHandle *rh = cls; struct AuthorityChain *ac; unsigned int i; - unsigned int j; - struct sockaddr *sa; - struct sockaddr_in v4; - struct sockaddr_in6 v6; - size_t sa_len; char *cname; struct VpnContext *vpn_ctx; const struct GNUNET_TUN_GnsVpnRecord *vpn; @@ -1532,126 +1686,67 @@ handle_gns_resolution_result (void *cls, return; case GNUNET_GNSRECORD_TYPE_GNS2DNS: { - char *ns; /* resolution continues within DNS */ - if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size) + struct Gns2DnsContext *g2dc; + char *ip; + char *at; + char *cp; + char *ns; + + cp = GNUNET_strndup (rd[i].data, + rd[i].data_size); + at = strchr (cp, '@'); + if (NULL == at) { GNUNET_break_op (0); rh->proc (rh->proc_cls, 0, NULL); GNS_resolver_lookup_cancel (rh); return; } - /* find associated A/AAAA record */ - sa = NULL; - sa_len = 0; - for (j=0;jproc (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; - off = 0; - ns = GNUNET_DNSPARSER_parse_name (rd[i].data, - rd[i].data_size, - &off); - if ( (NULL == ns) || - (off != rd[i].data_size) ) - { - GNUNET_break_op (0); /* record not well-formed */ - rh->proc (rh->proc_cls, 0, NULL); - GNS_resolver_lookup_cancel (rh); - GNUNET_free_non_null (ns); - GNUNET_free (ac); - return; - } - strcpy (ac->authority_info.dns_authority.name, - 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) ? "." : "", - ns); - GNUNET_free (ns); - 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); + *at = '\0'; + off = 0; + ns = GNUNET_DNSPARSER_parse_name (cp, + strlen (cp), + &off); + if ( (NULL == ns) || + (off != strlen (cp)) ) + { + GNUNET_break_op (0); /* record not well-formed */ + rh->proc (rh->proc_cls, 0, NULL); + GNS_resolver_lookup_cancel (rh); + GNUNET_free (cp); + return; + } + off++; /* skip '@' */ + ip = GNUNET_DNSPARSER_parse_name (cp, + strlen (at + 1), + &off); + if ( (NULL == ip) || + (off != rd[i].data_size) ) + { + GNUNET_break_op (0); /* record not well-formed */ + rh->proc (rh->proc_cls, 0, NULL); + GNS_resolver_lookup_cancel (rh); + GNUNET_free (ns); + GNUNET_free (cp); + return; + } + GNUNET_free (cp); + /* resolve 'ip' to determine the IP(s) of the DNS + resolver to use */ + g2dc = GNUNET_new (struct Gns2DnsContext); + g2dc->ns = ns; + g2dc->rh = GNUNET_new (struct GNS_ResolverHandle); + g2dc->rh->authority_zone = rh->ac_tail->authority_info.gns_authority; + g2dc->rh->name = ip; + g2dc->rh->name_resolution_pos = strlen (ip); + g2dc->rh->proc = &handle_gns2dns_result; + g2dc->rh->proc_cls = rh; + g2dc->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY; + g2dc->rh->only_cached = GNUNET_NO; + g2dc->rh->loop_limiter = rh->loop_limiter + 1; + rh->g2dc = g2dc; + start_resolver_lookup (g2dc->rh); return; } case GNUNET_DNSPARSER_TYPE_CNAME: @@ -2000,7 +2095,41 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh) { struct AuthorityChain *ac; char *y; + struct in_addr v4; + struct in6_addr v6; + if (1 == inet_pton (AF_INET, + rh->name, + &v4)) + { + /* name is IPv4 address, pretend it's an A record */ + struct GNUNET_GNSRECORD_Data rd; + + rd.data = &v4; + rd.data_size = sizeof (v4); + rd.expiration_time = UINT64_MAX; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + rd.flags = 0; + rh->proc (rh->proc_cls, 1, &rd); + GNS_resolver_lookup_cancel (rh); + return; + } + if (1 == inet_pton (AF_INET6, + rh->name, + &v6)) + { + /* name is IPv6 address, pretend it's an AAAA record */ + struct GNUNET_GNSRECORD_Data rd; + + rd.data = &v6; + rd.data_size = sizeof (v6); + rd.expiration_time = UINT64_MAX; + rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA; + rd.flags = 0; + rh->proc (rh->proc_cls, 1, &rd); + GNS_resolver_lookup_cancel (rh); + return; + } if ( ( (GNUNET_YES == is_canonical (rh->name)) && (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) || ( (GNUNET_YES != is_gnu_tld (rh->name)) && @@ -2143,6 +2272,23 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh) GNUNET_free (ac->label); GNUNET_free (ac); } + if (NULL != rh->g2dc) + { + /* rh->g2dc->rh is NOT in the DLL yet, so to enable us + using GNS_resolver_lookup_cancel here, we need to + add it first... */ + if (NULL != rh->g2dc->rh) + { + GNUNET_CONTAINER_DLL_insert (rlh_head, + rlh_tail, + rh->g2dc->rh); + GNS_resolver_lookup_cancel (rh->g2dc->rh); + rh->g2dc->rh = NULL; + } + GNUNET_free (rh->g2dc->ns); + GNUNET_free (rh->g2dc); + rh->g2dc = NULL; + } if (GNUNET_SCHEDULER_NO_TASK != rh->task_id) { GNUNET_SCHEDULER_cancel (rh->task_id); diff --git a/src/gns/test_gns_ns_lookup.sh b/src/gns/test_gns_ns_lookup.sh index 878d2aad4..fe5e2132d 100755 --- a/src/gns/test_gns_ns_lookup.sh +++ b/src/gns/test_gns_ns_lookup.sh @@ -1,34 +1,57 @@ #!/bin/bash trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT rm -r `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f` -TEST_DOMAIN="www.homepage.gnu" -TEST_DOMAIN_ALT="homepage.gnu" -TEST_DOMAIN_ALT2="uk.homepage.gnu" +# IP address of 'uk.gnunet.org' TEST_IP_ALT2="81.187.252.184" +# IP address of 'www.gnunet.org' TEST_IP="131.159.74.67" +# IPv6 address of 'gnunet.org' TEST_IP6="2001:4ca0:2001:42:225:90ff:fe6b:d60" -TEST_IP_GNS2DNS="184.172.157.218" +# permissive DNS resolver we will use for the test +TEST_IP_GNS2DNS="8.8.8.8" + +# main label used during resolution TEST_RECORD_NAME="homepage" -TEST_RECORD_GNS2DNS="gnunet.org" +# various names we will use for resolution +TEST_DOMAIN="www.${TEST_RECORD_NAME}.gnu" +TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.gnu" +TEST_DOMAIN_ALT2="uk.${TEST_RECORD_NAME}.gnu" + +# helper record for pointing to the DNS resolver +TEST_RESOLVER_LABEL="resolver" +# GNS2DNS record value: delegate to DNS domain 'gnunet.org' +# using the TEST_RESOLVER_LABEL DNS server for resolution +TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.+" + gnunet-arm -s -c test_gns_lookup.conf gnunet-identity -C testego -c test_gns_lookup.conf -gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf + +# set IP address for DNS resolver for resolving in gnunet.org domain +gnunet-namestore -p -z testego -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf +# map 'homepage.gnu' to 'gnunet.org' in DNS gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf + +# lookup 'www.gnunet.org', IPv4 RES_IP=$(timeout 5 gnunet-gns --raw -z testego -u $TEST_DOMAIN -t A -c test_gns_lookup.conf) +# lookup 'www.gnunet.org', IPv6 RES_IP6=$(timeout 5 gnunet-gns --raw -z testego -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf) +# lookup 'gnunet.org', IPv4 RES_IP_ALT=$(timeout 5 gnunet-gns --raw -z testego -u $TEST_DOMAIN_ALT -t A -c test_gns_lookup.conf) +# lookup 'uk.gnunet.org', IPv4 RES_IP_ALT2=$(timeout 5 gnunet-gns --raw -z testego -u $TEST_DOMAIN_ALT2 -t A -c test_gns_lookup.conf) -gnunet-namestore -z testego -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf + +# clean up +gnunet-namestore -z testego -d -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf gnunet-namestore -z testego -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf gnunet-identity -D testego -c test_gns_lookup.conf gnunet-arm -e -c test_gns_lookup.conf - +ret=0 if [ "$RES_IP" == "$TEST_IP" ] then echo "PASS: Resolved $TEST_DOMAIN to $RES_IP." else echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP." - exit 1 + ret=1 fi if [ "$RES_IP6" == "$TEST_IP6" ] @@ -36,7 +59,7 @@ then echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6." else echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6." - exit 1 + ret=1 fi if [ "$RES_IP_ALT" == "$TEST_IP" ] @@ -44,14 +67,14 @@ then echo "PASS: Resolved $TEST_DOMAIN_ALT to $RES_IP_ALT." else echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT, got $RES_IP_ALT, wanted $TEST_IP." - exit 1 + ret=1 fi if [ "$RES_IP_ALT2" == "$TEST_IP_ALT2" ] then echo "PASS: Resolved $TEST_DOMAIN_ALT2 to $RES_IP_ALT2." - exit 0 else echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT2, got $RES_IP_ALT2, wanted $TEST_IP_ALT2." - exit 1 + ret=1 fi +exit $ret