From 050506341c887550f3558a5a4bdebd9b8d3742f6 Mon Sep 17 00:00:00 2001 From: saradickinson Date: Tue, 23 Sep 2014 11:36:26 +0000 Subject: [PATCH 1/2] First pass of implementing per query namespace lookup for stub resolver. Also a getdns local namespace lookup is now used for all sync calls. --- src/context.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++- src/context.h | 6 ++ src/sync.c | 152 ++++++++++++++++++++++++++++++-------------- 3 files changed, 280 insertions(+), 51 deletions(-) diff --git a/src/context.c b/src/context.c index 606dd3fa..01672906 100755 --- a/src/context.c +++ b/src/context.c @@ -52,8 +52,14 @@ void *plain_mem_funcs_user_arg = MF_PLAIN; +struct host_name_addr_type { + ldns_rdf * host_name; + ldns_rr_type addr_type; +}; + /* Private functions */ getdns_return_t create_default_namespaces(struct getdns_context *context); +getdns_return_t create_local_hosts(struct getdns_context *context); static struct getdns_list *create_default_root_servers(void); static getdns_return_t add_ip_str(struct getdns_dict *); static struct getdns_dict *create_ipaddr_dict_from_rdf(struct getdns_context *, @@ -63,6 +69,7 @@ static struct getdns_list *create_from_ldns_list(struct getdns_context *, static getdns_return_t set_os_defaults(struct getdns_context *); static int transaction_id_cmp(const void *, const void *); static int timeout_cmp(const void *, const void *); +static int local_host_cmp(const void *, const void *); static void dispatch_updated(struct getdns_context *, uint16_t); static void cancel_dns_req(getdns_dns_req *); static void cancel_outstanding_requests(struct getdns_context*, int); @@ -107,6 +114,63 @@ create_default_namespaces(struct getdns_context *context) return GETDNS_RETURN_GOOD; } +/** + * Helper to get contents from hosts file + */ +getdns_return_t +create_local_hosts(struct getdns_context *context) +{ + + ldns_rr_list * host_names = ldns_get_rr_list_hosts_frm_file(NULL); + if (host_names == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + + /*TODO: free up memory on error paths*/ + //ldns_rr_list_print(stderr, host_names); + + /* We have a 1:1 list of name -> ip address where there is an + underlying many to many relationship. Need to create a lookup of + (unique name + A/AAAA)-> list of IPV4/IPv6 ip addresses*/ + for (int i = 0 ; imy_mf, struct host_name_addr_type); + if (lh_key == NULL) + return GETDNS_RETURN_MEMORY_ERROR; + lh_key->host_name = owner; + lh_key->addr_type = ldns_rr_get_type(rr); + ldns_rbnode_t *result_node = ldns_rbtree_search(context->local_hosts, lh_key); + if (result_node) { + if (!ldns_rr_list_push_rr ((ldns_rr_list *)result_node->data, ldns_rr_clone(rr))) + return GETDNS_RETURN_GENERIC_ERROR; + } + else { + ldns_rr_list *address_list = ldns_rr_list_new (); + if (!ldns_rr_list_push_rr (address_list, ldns_rr_clone(rr))) + return GETDNS_RETURN_GENERIC_ERROR; + + ldns_rbnode_t *node = GETDNS_MALLOC(context->my_mf, ldns_rbnode_t); + if (!node) { + return GETDNS_RETURN_GENERIC_ERROR; + } + node->key = lh_key; + node->data = address_list; + if (!ldns_rbtree_insert(context->local_hosts, node)) { + /* free the node */ + GETDNS_FREE(context->my_mf, node); + return GETDNS_RETURN_GENERIC_ERROR; + } + } + } + + return GETDNS_RETURN_GOOD; +} + + /** * Helper to get the default root servers. * TODO: Implement @@ -385,6 +449,27 @@ timeout_cmp(const void *to1, const void *to2) } } +static int +local_host_cmp(const void *id1, const void *id2) +{ + if (id1 == NULL && id2 == NULL) { + return 0; + } else if (id1 == NULL && id2 != NULL) { + return 1; + } else if (id1 != NULL && id2 == NULL) { + return -1; + } else { + const struct host_name_addr_type *hn1 = (const struct host_name_addr_type*) id1; + const struct host_name_addr_type *hn2 = (const struct host_name_addr_type*) id2; + if ((ldns_rr_type) hn1->addr_type < (ldns_rr_type) hn2->addr_type) + return -1; + if ((ldns_rr_type) hn1->addr_type > (ldns_rr_type) hn2->addr_type) + return 1; + return (ldns_rdf_compare((const ldns_rdf *) hn1->host_name, + (const ldns_rdf *) hn2->host_name)); + } +} + static ldns_rbtree_t* create_ldns_rbtree(getdns_context * context, int(*cmpf)(const void *, const void *)) { @@ -444,6 +529,7 @@ getdns_context_create_with_extended_memory_functions( result->outbound_requests = create_ldns_rbtree(result, transaction_id_cmp); result->timeouts_by_time = create_ldns_rbtree(result, timeout_cmp); result->timeouts_by_id = create_ldns_rbtree(result, transaction_id_cmp); + result->local_hosts = create_ldns_rbtree(result, local_host_cmp); result->resolution_type = GETDNS_RESOLUTION_RECURSING; @@ -484,7 +570,8 @@ getdns_context_create_with_extended_memory_functions( result->return_dnssec_status = GETDNS_EXTENSION_FALSE; if (!result->outbound_requests || !result->timeouts_by_id || - !result->timeouts_by_time) { + !result->timeouts_by_time || + !result->local_hosts) { getdns_context_destroy(result); return GETDNS_RETURN_MEMORY_ERROR; } @@ -495,7 +582,12 @@ getdns_context_create_with_extended_memory_functions( return GETDNS_RETURN_GENERIC_ERROR; } /* ldns context is initialised to NULL here and rebuilt later if needed */ - result->ldns_res = NULL; + result->ldns_res = NULL; + + if(create_local_hosts(result) != GETDNS_RETURN_GOOD) { + getdns_context_destroy(result); + return GETDNS_RETURN_GENERIC_ERROR; + } *context = result; @@ -591,6 +683,10 @@ getdns_context_destroy(struct getdns_context *context) GETDNS_FREE(context->my_mf, context->timeouts_by_id); if (context->timeouts_by_time) GETDNS_FREE(context->my_mf, context->timeouts_by_time); + if (context->local_hosts) { + /*TODO: deep free of this tree*/ + GETDNS_FREE(context->my_mf, context->local_hosts); + } GETDNS_FREE(context->my_mf, context); } /* getdns_context_destroy */ @@ -2023,4 +2119,77 @@ getdns_context_set_use_threads(getdns_context* context, int use_threads) { return r == 0 ? GETDNS_RETURN_GOOD : GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } +getdns_return_t +getdns_context_local_namespace_resolve(getdns_dns_req* req, + struct getdns_context *context) +{ + + /* NOTE: This only returns GETDNS_RETURN_GOOD if it finds answers for all the + netreq that it tries */ + /*TODO: free memory on error paths*/ + + getdns_network_req *netreq = req->first_req; + while (netreq) { + /*This request may have already been answered by another namespace*/ + if (netreq->result) { + netreq = netreq->next; + continue; + } + if (netreq->request_type != GETDNS_RRTYPE_A && netreq->request_type != GETDNS_RRTYPE_AAAA) + return GETDNS_RETURN_GENERIC_ERROR; + + /*Do the lookup*/ + ldns_rdf *query_name = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, req->name); + struct host_name_addr_type *lh_key = + GETDNS_MALLOC(context->my_mf, struct host_name_addr_type); + if (lh_key == NULL) + return GETDNS_RETURN_MEMORY_ERROR; + lh_key->host_name = query_name; + lh_key->addr_type = netreq->request_type; + ldns_rbnode_t *result_node = ldns_rbtree_search(context->local_hosts, lh_key); + if (!result_node) { + ldns_rdf_deep_free(query_name); + return GETDNS_RETURN_GENERIC_ERROR; + } + + /*Fabricate the result packet*/ + ldns_pkt *answer_pkt; + ldns_rr *question_rr; + ldns_rr_list *answer_qr; + ldns_rr_list *answer_an; + ldns_rr_list *answer_ns; + ldns_rr_list *answer_ad; + + question_rr = ldns_rr_new_frm_type(netreq->request_type); + ldns_rr_set_class(question_rr, netreq->request_class); + ldns_rr_set_owner(question_rr, query_name); + ldns_rr_set_rd_count (question_rr, (size_t)0); + answer_qr = ldns_rr_list_new(); + if (!ldns_rr_list_push_rr (answer_qr, question_rr)) { + ldns_rdf_deep_free(query_name); + ldns_rr_free(question_rr); + ldns_rr_list_deep_free(answer_qr); + return GETDNS_RETURN_GENERIC_ERROR; + } + + answer_an = ldns_rr_list_clone((ldns_rr_list *)result_node->data); + answer_ns = ldns_rr_list_new(); + answer_ad = ldns_rr_list_new(); + + answer_pkt = ldns_pkt_new(); + ldns_pkt_set_qr(answer_pkt, 1); + ldns_pkt_set_aa(answer_pkt, 1); + + ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr); + ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an); + ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns); + ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad); + + netreq->result = answer_pkt; + netreq = netreq->next; + } + return GETDNS_RETURN_GOOD; + +} + /* context.c */ diff --git a/src/context.h b/src/context.h index 17c7bd6c..78dac09b 100755 --- a/src/context.h +++ b/src/context.h @@ -99,6 +99,8 @@ struct getdns_context { /* The underlying contexts that do the real work */ struct ub_ctx *unbound_ctx; ldns_resolver *ldns_res; + /* A tree to hold local host information*/ + struct ldns_rbtree_t *local_hosts; int has_ta; /* No DNSSEC without trust anchor */ int return_dnssec_status; @@ -183,6 +185,10 @@ getdns_return_t getdns_context_schedule_timeout(struct getdns_context* context, getdns_return_t getdns_context_clear_timeout(struct getdns_context* context, getdns_transaction_t id); +/* perform name resolution in /etc/hosts */ +getdns_return_t getdns_context_local_namespace_resolve(getdns_dns_req* req, + struct getdns_context *context); + int filechg_check(struct getdns_context *context, struct filechg *fchg); #endif /* _GETDNS_CONTEXT_H_ */ diff --git a/src/sync.c b/src/sync.c index 9214f281..e04e1913 100755 --- a/src/sync.c +++ b/src/sync.c @@ -56,6 +56,11 @@ static getdns_return_t submit_request_sync_rec( getdns_network_req *netreq = req->first_req; while (netreq) { + /*This request may have already been answered by another namespace*/ + if (netreq->result) { + netreq = netreq->next; + continue; + } int r = ub_timed_resolve(req->context->unbound_ctx, req->name, netreq->request_type, @@ -85,6 +90,11 @@ static getdns_return_t submit_request_sync_stub( struct timeval tv; while (netreq) { + /*This request may have already been answered by another namespace*/ + if (netreq->result) { + netreq = netreq->next; + continue; + } qname = ldns_dname_new_frm_str(req->name); qflags = qflags | LDNS_RD; /* TODO: Use timeout properly - create a ldns_timed_resolve function */ @@ -95,6 +105,10 @@ static getdns_return_t submit_request_sync_stub( netreq->result = ldns_resolver_query( req->context->ldns_res, qname, netreq->request_type, netreq->request_class, qflags); + /*TODO: The rec unbound case always sends DO=1 and then + getdns_apply_network_result sets these values...*/ + // netreq->secure = ; + // netreq->bogus = ; ldns_rdf_deep_free(qname); qname = NULL; @@ -118,6 +132,86 @@ static getdns_return_t submit_request_sync( } } +getdns_return_t +getdns_general_sync_ns(struct getdns_context *context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + struct getdns_dict **response, + bool usenamespaces) +{ + getdns_dns_req *req; + getdns_return_t response_status; + uint64_t timeout; + + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(response, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(name, GETDNS_RETURN_INVALID_PARAMETER); + + timeout = context->timeout; + response_status = validate_dname(name); + if (response_status != GETDNS_RETURN_GOOD) + return response_status; + + response_status = validate_extensions(extensions); + if (response_status != GETDNS_RETURN_GOOD) + return response_status; + + /* Set up the context assuming we won't use the specified namespaces. + This is (currently) identical to setting up a pure DNS namespace */ + response_status = getdns_context_prepare_for_resolution(context, 0); + if (response_status != GETDNS_RETURN_GOOD) + return response_status; + + /* create the request */ + req = dns_req_new(context, name, request_type, extensions); + if (!req) + return GETDNS_RETURN_MEMORY_ERROR; + + /*TODO: Would be tidier to loop over the netreq here trying each namespace + rather then trying each namespace...*/ + + /* resolve using the appropriate namespace*/ + if (!usenamespaces) { + response_status = submit_request_sync(req, context); + } else { + for (int i = 0; i < context->namespace_count; i++) { + switch (context->namespaces[i]) { + case GETDNS_NAMESPACE_LOCALNAMES: + response_status = getdns_context_local_namespace_resolve(req, context); + break; + + case GETDNS_NAMESPACE_DNS: + response_status = submit_request_sync(req, context); + break; + + default: + response_status = GETDNS_RETURN_BAD_CONTEXT; + break; + } + /* If we have all good responses break out the for loop as we are done, + but if we don't then give the next namespace a try*/ + if (response_status == GETDNS_RETURN_GOOD) + break; + } + } + + if (response_status == GETDNS_RETURN_GOOD) { + if (is_extension_set(req->extensions, + "dnssec_return_validation_chain")) + *response = priv_getdns_get_validation_chain_sync(req, &timeout); + else + *response = create_getdns_response(req); + + } else if (response_status == GETDNS_RESPSTATUS_ALL_TIMEOUT) { + *response = create_getdns_response(req); + response_status = GETDNS_RETURN_GOOD; + } + + dns_req_free(req); + return response_status; +} + getdns_return_t getdns_general_sync(struct getdns_context *context, const char *name, @@ -125,49 +219,9 @@ getdns_general_sync(struct getdns_context *context, struct getdns_dict *extensions, struct getdns_dict **response) { - getdns_dns_req *req; - getdns_return_t response_status; - uint64_t timeout; - - RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); - RETURN_IF_NULL(response, GETDNS_RETURN_INVALID_PARAMETER); - RETURN_IF_NULL(name, GETDNS_RETURN_INVALID_PARAMETER); - - timeout = context->timeout; - response_status = validate_dname(name); - if (response_status != GETDNS_RETURN_GOOD) - return response_status; - - response_status = validate_extensions(extensions); - if (response_status != GETDNS_RETURN_GOOD) - return response_status; - - /* general, so without dns lookup (no namespaces) */; - response_status = getdns_context_prepare_for_resolution(context, 0); - if (response_status != GETDNS_RETURN_GOOD) - return response_status; - - /* for each netreq we call ub_ctx_resolve */ - /* request state */ - req = dns_req_new(context, name, request_type, extensions); - if (!req) - return GETDNS_RETURN_MEMORY_ERROR; - - response_status = submit_request_sync(req, context); - if (response_status == GETDNS_RETURN_GOOD) { - if (is_extension_set(req->extensions, - "dnssec_return_validation_chain")) - *response = priv_getdns_get_validation_chain_sync(req, &timeout); - else - *response = create_getdns_response(req); - - } else if (response_status == GETDNS_RESPSTATUS_ALL_TIMEOUT) { - *response = create_getdns_response(req); - response_status = GETDNS_RETURN_GOOD; - } - - dns_req_free(req); - return response_status; + /* general, so without dns lookup (no namespaces) */; + return getdns_general_sync_ns(context, name, request_type, + extensions, response, false); } getdns_return_t @@ -185,8 +239,8 @@ getdns_address_sync(struct getdns_context *context, GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6, GETDNS_EXTENSION_TRUE); getdns_return_t result = - getdns_general_sync(context, name, GETDNS_RRTYPE_A, - extensions, response); + getdns_general_sync_ns(context, name, GETDNS_RRTYPE_A, + extensions, response, true); if (cleanup_extensions) { getdns_dict_destroy(extensions); } @@ -226,8 +280,8 @@ getdns_hostname_sync(struct getdns_context *context, return GETDNS_RETURN_INVALID_PARAMETER; if ((name = reverse_address(address_data)) == NULL) return GETDNS_RETURN_INVALID_PARAMETER; - retval = getdns_general_sync(context, name, req_type, extensions, - response); + retval = getdns_general_sync_ns(context, name, req_type, extensions, + response, true); free(name); return retval; } @@ -239,8 +293,8 @@ getdns_service_sync(struct getdns_context *context, struct getdns_dict ** response) { - return getdns_general_sync(context, name, GETDNS_RRTYPE_SRV, - extensions, response); + return getdns_general_sync_ns(context, name, GETDNS_RRTYPE_SRV, + extensions, response, true); } From d9addba883d5d95b9ab1156d5fa53116ac83b98e Mon Sep 17 00:00:00 2001 From: saradickinson Date: Thu, 25 Sep 2014 14:25:22 +0000 Subject: [PATCH 2/2] Second pass at implementing per query namespaces! --- src/context.c | 106 ++++---- src/context.h | 1 + src/sync.c | 28 +- src/test/Makefile.in | 5 +- src/test/check_getdns_address_sync.h | 7 +- src/test/check_getdns_common.c | 19 ++ src/test/check_getdns_common.h | 14 + src/test/tests_namespaces.c | 142 ++++++++++ src/test/tests_namespaces.good | 379 +++++++++++++++++++++++++++ src/util-internal.c | 74 ++++++ src/util-internal.h | 2 + 11 files changed, 700 insertions(+), 77 deletions(-) mode change 100644 => 100755 src/test/Makefile.in mode change 100644 => 100755 src/test/check_getdns_address_sync.h mode change 100644 => 100755 src/test/check_getdns_common.c mode change 100644 => 100755 src/test/check_getdns_common.h create mode 100755 src/test/tests_namespaces.c create mode 100755 src/test/tests_namespaces.good mode change 100644 => 100755 src/util-internal.c mode change 100644 => 100755 src/util-internal.h diff --git a/src/context.c b/src/context.c index 01672906..1ac934d8 100755 --- a/src/context.c +++ b/src/context.c @@ -60,6 +60,7 @@ struct host_name_addr_type { /* Private functions */ getdns_return_t create_default_namespaces(struct getdns_context *context); getdns_return_t create_local_hosts(struct getdns_context *context); +getdns_return_t destroy_local_hosts(struct getdns_context *context); static struct getdns_list *create_default_root_servers(void); static getdns_return_t add_ip_str(struct getdns_dict *); static struct getdns_dict *create_ipaddr_dict_from_rdf(struct getdns_context *, @@ -96,6 +97,16 @@ static getdns_return_t set_ldns_nameservers(struct getdns_context*, /* Stuff to make it compile pedantically */ #define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code; +static void destroy_local_host(ldns_rbnode_t * node, void *arg) +{ + struct getdns_context *context = (struct getdns_context *) arg; + + struct host_name_addr_type *lh = (struct host_name_addr_type *) node->key; + ldns_rdf_free(lh->host_name); + ldns_rr_list_deep_free((ldns_rr_list *)node->data); + GETDNS_FREE(context->mf, node); +} + /** * Helper to get default lookup namespaces. * TODO: Determine from OS @@ -120,14 +131,11 @@ create_default_namespaces(struct getdns_context *context) getdns_return_t create_local_hosts(struct getdns_context *context) { - + ldns_rr_list * host_names = ldns_get_rr_list_hosts_frm_file(NULL); if (host_names == NULL) return GETDNS_RETURN_GENERIC_ERROR; - /*TODO: free up memory on error paths*/ - //ldns_rr_list_print(stderr, host_names); - /* We have a 1:1 list of name -> ip address where there is an underlying many to many relationship. Need to create a lookup of (unique name + A/AAAA)-> list of IPV4/IPv6 ip addresses*/ @@ -155,22 +163,21 @@ create_local_hosts(struct getdns_context *context) ldns_rbnode_t *node = GETDNS_MALLOC(context->my_mf, ldns_rbnode_t); if (!node) { - return GETDNS_RETURN_GENERIC_ERROR; + return GETDNS_RETURN_MEMORY_ERROR; } node->key = lh_key; node->data = address_list; if (!ldns_rbtree_insert(context->local_hosts, node)) { - /* free the node */ GETDNS_FREE(context->my_mf, node); return GETDNS_RETURN_GENERIC_ERROR; } } } + ldns_rr_list_deep_free(host_names); return GETDNS_RETURN_GOOD; } - /** * Helper to get the default root servers. * TODO: Implement @@ -684,7 +691,8 @@ getdns_context_destroy(struct getdns_context *context) if (context->timeouts_by_time) GETDNS_FREE(context->my_mf, context->timeouts_by_time); if (context->local_hosts) { - /*TODO: deep free of this tree*/ + ldns_traverse_postorder(context->local_hosts, + destroy_local_host, context); GETDNS_FREE(context->my_mf, context->local_hosts); } @@ -2120,75 +2128,57 @@ getdns_context_set_use_threads(getdns_context* context, int use_threads) { } getdns_return_t -getdns_context_local_namespace_resolve(getdns_dns_req* req, +getdns_context_local_namespace_resolve(getdns_dns_req* req, + struct getdns_dict **response, struct getdns_context *context) { - /* NOTE: This only returns GETDNS_RETURN_GOOD if it finds answers for all the - netreq that it tries */ - /*TODO: free memory on error paths*/ + ldns_rr_list *result_list = NULL; + struct host_name_addr_type *lh_key = + GETDNS_MALLOC(context->my_mf, struct host_name_addr_type); + if (lh_key == NULL) + return GETDNS_RETURN_MEMORY_ERROR; getdns_network_req *netreq = req->first_req; while (netreq) { - /*This request may have already been answered by another namespace*/ - if (netreq->result) { + if (netreq->request_type != GETDNS_RRTYPE_A && + netreq->request_type != GETDNS_RRTYPE_AAAA) { netreq = netreq->next; continue; } - if (netreq->request_type != GETDNS_RRTYPE_A && netreq->request_type != GETDNS_RRTYPE_AAAA) - return GETDNS_RETURN_GENERIC_ERROR; /*Do the lookup*/ ldns_rdf *query_name = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, req->name); - struct host_name_addr_type *lh_key = - GETDNS_MALLOC(context->my_mf, struct host_name_addr_type); - if (lh_key == NULL) - return GETDNS_RETURN_MEMORY_ERROR; + if (!query_name) { + GETDNS_FREE(context->my_mf, lh_key); + return GETDNS_RETURN_GENERIC_ERROR; + } lh_key->host_name = query_name; lh_key->addr_type = netreq->request_type; ldns_rbnode_t *result_node = ldns_rbtree_search(context->local_hosts, lh_key); - if (!result_node) { - ldns_rdf_deep_free(query_name); - return GETDNS_RETURN_GENERIC_ERROR; + if (result_node) { + if (result_list == NULL) + result_list = + ldns_rr_list_clone((ldns_rr_list *)result_node->data); + else { + if (!ldns_rr_list_cat(result_list, (ldns_rr_list *)result_node->data)) { + GETDNS_FREE(context->my_mf, lh_key); + ldns_rdf_deep_free(query_name); + return GETDNS_RETURN_GENERIC_ERROR; + } + } } - /*Fabricate the result packet*/ - ldns_pkt *answer_pkt; - ldns_rr *question_rr; - ldns_rr_list *answer_qr; - ldns_rr_list *answer_an; - ldns_rr_list *answer_ns; - ldns_rr_list *answer_ad; - - question_rr = ldns_rr_new_frm_type(netreq->request_type); - ldns_rr_set_class(question_rr, netreq->request_class); - ldns_rr_set_owner(question_rr, query_name); - ldns_rr_set_rd_count (question_rr, (size_t)0); - answer_qr = ldns_rr_list_new(); - if (!ldns_rr_list_push_rr (answer_qr, question_rr)) { - ldns_rdf_deep_free(query_name); - ldns_rr_free(question_rr); - ldns_rr_list_deep_free(answer_qr); - return GETDNS_RETURN_GENERIC_ERROR; - } - - answer_an = ldns_rr_list_clone((ldns_rr_list *)result_node->data); - answer_ns = ldns_rr_list_new(); - answer_ad = ldns_rr_list_new(); - - answer_pkt = ldns_pkt_new(); - ldns_pkt_set_qr(answer_pkt, 1); - ldns_pkt_set_aa(answer_pkt, 1); - - ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr); - ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an); - ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns); - ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad); - - netreq->result = answer_pkt; + ldns_rdf_deep_free(query_name); netreq = netreq->next; } - return GETDNS_RETURN_GOOD; + + GETDNS_FREE(context->my_mf, lh_key); + if (result_list == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + + *response = create_getdns_response_from_rr_list(req, result_list); + return response ? GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR; } diff --git a/src/context.h b/src/context.h index 78dac09b..ad7f6597 100755 --- a/src/context.h +++ b/src/context.h @@ -187,6 +187,7 @@ getdns_return_t getdns_context_clear_timeout(struct getdns_context* context, /* perform name resolution in /etc/hosts */ getdns_return_t getdns_context_local_namespace_resolve(getdns_dns_req* req, + struct getdns_dict **response, struct getdns_context *context); int filechg_check(struct getdns_context *context, struct filechg *fchg); diff --git a/src/sync.c b/src/sync.c index e04e1913..82ebacdd 100755 --- a/src/sync.c +++ b/src/sync.c @@ -56,11 +56,6 @@ static getdns_return_t submit_request_sync_rec( getdns_network_req *netreq = req->first_req; while (netreq) { - /*This request may have already been answered by another namespace*/ - if (netreq->result) { - netreq = netreq->next; - continue; - } int r = ub_timed_resolve(req->context->unbound_ctx, req->name, netreq->request_type, @@ -90,11 +85,6 @@ static getdns_return_t submit_request_sync_stub( struct timeval tv; while (netreq) { - /*This request may have already been answered by another namespace*/ - if (netreq->result) { - netreq = netreq->next; - continue; - } qname = ldns_dname_new_frm_str(req->name); qflags = qflags | LDNS_RD; /* TODO: Use timeout properly - create a ldns_timed_resolve function */ @@ -168,9 +158,6 @@ getdns_general_sync_ns(struct getdns_context *context, if (!req) return GETDNS_RETURN_MEMORY_ERROR; - /*TODO: Would be tidier to loop over the netreq here trying each namespace - rather then trying each namespace...*/ - /* resolve using the appropriate namespace*/ if (!usenamespaces) { response_status = submit_request_sync(req, context); @@ -178,10 +165,20 @@ getdns_general_sync_ns(struct getdns_context *context, for (int i = 0; i < context->namespace_count; i++) { switch (context->namespaces[i]) { case GETDNS_NAMESPACE_LOCALNAMES: - response_status = getdns_context_local_namespace_resolve(req, context); + response_status = getdns_context_local_namespace_resolve(req, + response, + context); + /* For a local lookup the response is populated directly*/ + if (response_status == GETDNS_RETURN_GOOD) { + dns_req_free(req); + return response_status; + } break; case GETDNS_NAMESPACE_DNS: + /* TODO: We will get a good return code here even if the name is + not found (NXDOMAIN). We should consider if this means we + go onto the next namespace instead of returning*/ response_status = submit_request_sync(req, context); break; @@ -189,13 +186,14 @@ getdns_general_sync_ns(struct getdns_context *context, response_status = GETDNS_RETURN_BAD_CONTEXT; break; } - /* If we have all good responses break out the for loop as we are done, + /* If we have a good response break out the for loop as we are done, but if we don't then give the next namespace a try*/ if (response_status == GETDNS_RETURN_GOOD) break; } } + /* Only get here if the response came from the DNS namespace*/ if (response_status == GETDNS_RETURN_GOOD) { if (is_extension_set(req->extensions, "dnssec_return_validation_chain")) diff --git a/src/test/Makefile.in b/src/test/Makefile.in old mode 100644 new mode 100755 index 02534e4f..8bec819b --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -58,7 +58,7 @@ CC=@CC@ CFLAGS=@CFLAGS@ -Wall -I.. -I$(srcdir)/.. -I$(srcdir) -std=c99 $(cflags) LDFLAGS=@LDFLAGS@ -L.. LDLIBS=-lgetdns @LIBS@ -lcheck -lm -lrt -PROGRAMS=tests_dict tests_list tests_stub_async tests_stub_sync check_getdns tests_dnssec $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) +PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync check_getdns tests_dnssec $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) .SUFFIXES: .c .o .a .lo .h @@ -78,6 +78,9 @@ tests_dict: tests_dict.lo testmessages.lo tests_list: tests_list.lo testmessages.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ tests_list.lo testmessages.lo +tests_namespaces: tests_namespaces.lo + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ tests_namespaces.lo + tests_stub_async: tests_stub_async.lo testmessages.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ tests_stub_async.lo testmessages.lo diff --git a/src/test/check_getdns_address_sync.h b/src/test/check_getdns_address_sync.h old mode 100644 new mode 100755 index 9c4877f0..542f3e1c --- a/src/test/check_getdns_address_sync.h +++ b/src/test/check_getdns_address_sync.h @@ -130,10 +130,11 @@ ASSERT_RC(getdns_address_sync(context, "localhost", NULL, &response), GETDNS_RETURN_GOOD, "Return code from getdns_address_sync()"); - EXTRACT_RESPONSE; + EXTRACT_LOCAL_RESPONSE; - assert_noerror( &ex_response); - assert_address_in_answer(&ex_response, TRUE, TRUE); + /* TODO: create reduced forms of these tests for local responses*/ + //assert_noerror( &ex_response); + //assert_address_in_answer(&ex_response, TRUE, TRUE); CONTEXT_DESTROY; diff --git a/src/test/check_getdns_common.c b/src/test/check_getdns_common.c old mode 100644 new mode 100755 index 38a9fed3..51493ae3 --- a/src/test/check_getdns_common.c +++ b/src/test/check_getdns_common.c @@ -103,6 +103,25 @@ void extract_response(struct getdns_dict *response, struct extracted_response *e GETDNS_RETURN_GOOD, "Failed to extract \"status\""); } +/* + * extract_response extracts all of the various information + * a test may want to look at from the response. + */ +void extract_local_response(struct getdns_dict *response, struct extracted_response *ex_response) +{ + ck_assert_msg(response != NULL, "Response should not be NULL"); + + ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name), + GETDNS_RETURN_GOOD, "Failed to extract \"top canonical_name\""); + + ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers), + GETDNS_RETURN_GOOD, "Failed to extract \"just_address_answers\""); + ck_assert_msg(ex_response->just_address_answers != NULL, "just_address_answers should not be NULL"); + + ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status), + GETDNS_RETURN_GOOD, "Failed to extract \"status\""); +} + /* * assert_noerror asserts that the rcode is 0 */ diff --git a/src/test/check_getdns_common.h b/src/test/check_getdns_common.h old mode 100644 new mode 100755 index 0e05e8d1..c2a8f30f --- a/src/test/check_getdns_common.h +++ b/src/test/check_getdns_common.h @@ -142,6 +142,14 @@ // // FUNCTION DECLARATIONS // + + #define EXTRACT_LOCAL_RESPONSE \ + struct extracted_response ex_response; \ + extract_local_response(response, &ex_response); + + // + // FUNCTION DECLARATIONS + // /* * extract_response extracts all of the various information @@ -149,6 +157,12 @@ */ void extract_response(struct getdns_dict *response, struct extracted_response *ex_response); + /* + * extract__local_response extracts all of the various information + * a test may want to look at from the response for a minimal, local. + */ + void extract_local_response(struct getdns_dict *response, struct extracted_response *ex_response); + /* * assert_noerror asserts that the rcode is 0. */ diff --git a/src/test/tests_namespaces.c b/src/test/tests_namespaces.c new file mode 100755 index 00000000..6eb0d3be --- /dev/null +++ b/src/test/tests_namespaces.c @@ -0,0 +1,142 @@ +/** + * \file + * unit tests for getdns_dict helper routines, these should be used to + * perform regression tests, output must be unchanged from canonical output + * stored with the sources + */ + +/* + * Copyright (c) 2013, NLNet Labs, Verisign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "testmessages.h" +#include "getdns/getdns.h" + +static void +print_response(struct getdns_dict * response) +{ + char *dict_str = getdns_pretty_print_dict(response); + if (dict_str) { + fprintf(stdout, "The packet %s\n", dict_str); + free(dict_str); + } +} + +int +main() +{ + + /* First up, use the default settings on a general and non-general call */ + + /* The namespaces used are per query depending on the type of method called. + But note that namespaces can only be changed before the first query.*/ + + /* Create the DNS context for this call */ + struct getdns_context *this_context = NULL; + getdns_return_t context_create_return = + getdns_context_create(&this_context, 1); + if (context_create_return != GETDNS_RETURN_GOOD) { + fprintf(stderr, "Trying to create the context failed: %d", + context_create_return); + return (GETDNS_RETURN_GENERIC_ERROR); + } + getdns_context_set_resolution_type(this_context, GETDNS_RESOLUTION_STUB); + + /* This will return a response with only the just_address_answers part + as the current implementaiton uses [LOCALNAMES, DNS]*/ + struct getdns_dict *response = NULL; + getdns_return_t ret = + getdns_address_sync(this_context, "localhost", NULL, &response); + + if (ret != GETDNS_RETURN_GOOD || response == NULL) { + fprintf(stderr, "Address sync returned error.\n"); + exit(EXIT_FAILURE); + } + print_response(response); + getdns_dict_destroy(response); + + /* This should fall back to a full DNS lookup*/ + ret = getdns_address_sync(this_context, "www.google.com", NULL, &response); + + if (ret != GETDNS_RETURN_GOOD || response == NULL) { + fprintf(stderr, "Address sync returned error.\n"); + exit(EXIT_FAILURE); + } + print_response(response); + getdns_dict_destroy(response); + + /* This should return a full DNS reply as the general lookups don't use + the namespaces, they just do pure DNS*/ + ret = getdns_general_sync(this_context, "localhost", GETDNS_RRTYPE_A, + NULL, &response); + if (ret != GETDNS_RETURN_GOOD || response == NULL) { + fprintf(stderr, "General sync over TCP returned error.\n"); + exit(EXIT_FAILURE); + } + print_response(response); + getdns_dict_destroy(response); + + /* Clean up */ + getdns_context_destroy(this_context); + + + /* Secondly, specify the namespace and see what happens*/ + + /* Create the DNS context for this call */ + struct getdns_context *next_context = NULL; + context_create_return = getdns_context_create(&next_context, 1); + if (context_create_return != GETDNS_RETURN_GOOD) { + fprintf(stderr, "Trying to create the context failed: %d", + context_create_return); + return (GETDNS_RETURN_GENERIC_ERROR); + } + getdns_context_set_resolution_type(next_context, GETDNS_RESOLUTION_STUB); + + getdns_namespace_t namespace_arr[2] = {GETDNS_NAMESPACE_DNS, GETDNS_NAMESPACE_LOCALNAMES}; + getdns_context_set_namespaces(next_context, 2,namespace_arr); + + /* This will return a full DNS reply*/ + ret = getdns_address_sync(next_context, "localhost", NULL, &response); + + if (ret != GETDNS_RETURN_GOOD || response == NULL) { + fprintf(stderr, "Address sync returned error.\n"); + exit(EXIT_FAILURE); + } + print_response(response); + getdns_dict_destroy(response); + + /* Clean up */ + getdns_context_destroy(next_context); + + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} /* main */ + +/* tests_stub_sync.c */ + diff --git a/src/test/tests_namespaces.good b/src/test/tests_namespaces.good new file mode 100755 index 00000000..979d88b5 --- /dev/null +++ b/src/test/tests_namespaces.good @@ -0,0 +1,379 @@ +The packet { + "canonical_name": , + "just_address_answers": + [ + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + } + ], + "replies_full": [], + "replies_tree": [], + "status": GETDNS_RESPSTATUS_GOOD +} +The packet { + "answer_type": GETDNS_NAMETYPE_DNS, + "canonical_name": , + "just_address_answers": + [ + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + } + ], + "replies_full": + [ + , + + ], + "replies_tree": + [ + { + "additional": [], + "answer": + [ + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_A + }, + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_A + }, + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_A + }, + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_A + }, + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_A + }, + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_A + } + ], + "answer_type": GETDNS_NAMETYPE_DNS, + "authority": [], + "canonical_name": , + "header": + { + "aa": 0, + "ad": 0, + "ancount": 6, + "arcount": 0, + "cd": 0, + "id": 55574, + "nscount": 0, + "opcode": GETDNS_OPCODE_QUERY, + "qdcount": 1, + "qr": 1, + "ra": 1, + "rcode": GETDNS_RCODE_NOERROR, + "rd": 1, + "tc": 0, + "z": 0 + }, + "question": + { + "qclass": GETDNS_RRCLASS_IN, + "qname": , + "qtype": GETDNS_RRTYPE_A + } + }, + { + "additional": [], + "answer": + [ + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv6_address": , + "rdata_raw": + }, + "ttl": 300, + "type": GETDNS_RRTYPE_AAAA + } + ], + "answer_type": GETDNS_NAMETYPE_DNS, + "authority": [], + "canonical_name": , + "header": + { + "aa": 0, + "ad": 0, + "ancount": 1, + "arcount": 0, + "cd": 0, + "id": 58601, + "nscount": 0, + "opcode": GETDNS_OPCODE_QUERY, + "qdcount": 1, + "qr": 1, + "ra": 1, + "rcode": GETDNS_RCODE_NOERROR, + "rd": 1, + "tc": 0, + "z": 0 + }, + "question": + { + "qclass": GETDNS_RRCLASS_IN, + "qname": , + "qtype": GETDNS_RRTYPE_AAAA + } + } + ], + "status": GETDNS_RESPSTATUS_GOOD +} +The packet { + "answer_type": GETDNS_NAMETYPE_DNS, + "canonical_name": , + "just_address_answers": + [ + { + "address_data": , + "address_type": + } + ], + "replies_full": + [ + + ], + "replies_tree": + [ + { + "additional": [], + "answer": + [ + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 86400, + "type": GETDNS_RRTYPE_A + } + ], + "answer_type": GETDNS_NAMETYPE_DNS, + "authority": [], + "canonical_name": , + "header": + { + "aa": 1, + "ad": 0, + "ancount": 1, + "arcount": 0, + "cd": 0, + "id": 21951, + "nscount": 0, + "opcode": GETDNS_OPCODE_QUERY, + "qdcount": 1, + "qr": 1, + "ra": 1, + "rcode": GETDNS_RCODE_NOERROR, + "rd": 1, + "tc": 0, + "z": 0 + }, + "question": + { + "qclass": GETDNS_RRCLASS_IN, + "qname": , + "qtype": GETDNS_RRTYPE_A + } + } + ], + "status": GETDNS_RESPSTATUS_GOOD +} +The packet { + "answer_type": GETDNS_NAMETYPE_DNS, + "canonical_name": , + "just_address_answers": + [ + { + "address_data": , + "address_type": + }, + { + "address_data": , + "address_type": + } + ], + "replies_full": + [ + , + + ], + "replies_tree": + [ + { + "additional": [], + "answer": + [ + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv4_address": , + "rdata_raw": + }, + "ttl": 86400, + "type": GETDNS_RRTYPE_A + } + ], + "answer_type": GETDNS_NAMETYPE_DNS, + "authority": [], + "canonical_name": , + "header": + { + "aa": 1, + "ad": 0, + "ancount": 1, + "arcount": 0, + "cd": 0, + "id": 36030, + "nscount": 0, + "opcode": GETDNS_OPCODE_QUERY, + "qdcount": 1, + "qr": 1, + "ra": 1, + "rcode": GETDNS_RCODE_NOERROR, + "rd": 1, + "tc": 0, + "z": 0 + }, + "question": + { + "qclass": GETDNS_RRCLASS_IN, + "qname": , + "qtype": GETDNS_RRTYPE_A + } + }, + { + "additional": [], + "answer": + [ + { + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "ipv6_address": , + "rdata_raw": + }, + "ttl": 10800, + "type": GETDNS_RRTYPE_AAAA + } + ], + "answer_type": GETDNS_NAMETYPE_DNS, + "authority": [], + "canonical_name": , + "header": + { + "aa": 1, + "ad": 0, + "ancount": 1, + "arcount": 0, + "cd": 0, + "id": 42580, + "nscount": 0, + "opcode": GETDNS_OPCODE_QUERY, + "qdcount": 1, + "qr": 1, + "ra": 1, + "rcode": GETDNS_RCODE_NOERROR, + "rd": 1, + "tc": 0, + "z": 0 + }, + "question": + { + "qclass": GETDNS_RRCLASS_IN, + "qname": , + "qtype": GETDNS_RRTYPE_AAAA + } + } + ], + "status": GETDNS_RESPSTATUS_GOOD +} \ No newline at end of file diff --git a/src/util-internal.c b/src/util-internal.c old mode 100644 new mode 100755 index d3ec698c..41ef7537 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -709,6 +709,80 @@ create_getdns_response(struct getdns_dns_req * completed_request) return result; } +/*This method can be used when e.g. a local lookup has been performed and the + result is simply a list of addresses (not a DNS packet)*/ +struct getdns_dict * +create_getdns_response_from_rr_list(struct getdns_dns_req * completed_request, + ldns_rr_list * response_list) +{ + struct getdns_dict *result = getdns_dict_create_with_context(completed_request->context); + struct getdns_list *replies_full = getdns_list_create_with_context( + completed_request->context); + struct getdns_list *replies_tree = getdns_list_create_with_context( + completed_request->context); + struct getdns_list *just_addrs = NULL; + char *canonical_name = NULL; + getdns_return_t r = 0; + + /* NOTE: With DNS packet, we ignore any DNSSEC related extensions since we + don't populate the replies full or tree at all*/ + + just_addrs = getdns_list_create_with_context(completed_request->context); + + do { + canonical_name = get_canonical_name(completed_request->name); + r = getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM, + canonical_name); + free(canonical_name); + if (r != GETDNS_RETURN_GOOD) { + break; + } + + /* For local lookups we don't set an answer_type as there isn't a + suitable one*/ + + r = add_only_addresses(just_addrs, response_list); + if (r != GETDNS_RETURN_GOOD) { + break; + } + + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_list(result, GETDNS_STR_KEY_REPLIES_TREE, + replies_tree); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_list(result, GETDNS_STR_KEY_REPLIES_FULL, + replies_full); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_list(result, GETDNS_STR_KEY_JUST_ADDRS, + just_addrs); + if (r != GETDNS_RETURN_GOOD) { + break; + } + + r = getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS, + GETDNS_RESPSTATUS_GOOD); + } while (0); + + /* cleanup */ + getdns_list_destroy(replies_tree); + getdns_list_destroy(replies_full); + getdns_list_destroy(just_addrs); + + if (r != 0) { + getdns_dict_destroy(result); + result = NULL; + } + + return result; +} + + /** * reverse an IP address for PTR lookup * @param address_data IP address to reverse diff --git a/src/util-internal.h b/src/util-internal.h old mode 100644 new mode 100755 index 1d6d1628..871ce5ed --- a/src/util-internal.h +++ b/src/util-internal.h @@ -102,6 +102,8 @@ getdns_return_t sockaddr_to_dict(struct getdns_context *context, struct getdns_dns_req; struct getdns_dict *create_getdns_response(struct getdns_dns_req *completed_request); +struct getdns_dict *create_getdns_response_from_rr_list(struct getdns_dns_req * completed_request, + ldns_rr_list * response_list); char *reverse_address(struct getdns_bindata *address_data);