Second pass at implementing per query namespaces!

This commit is contained in:
saradickinson 2014-09-25 14:25:22 +00:00
parent 050506341c
commit d9addba883
11 changed files with 700 additions and 77 deletions

View File

@ -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
@ -125,9 +136,6 @@ create_local_hosts(struct getdns_context *context)
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);
}
@ -2121,74 +2129,56 @@ getdns_context_set_use_threads(getdns_context* context, int use_threads) {
getdns_return_t
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;
}

View File

@ -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);

View File

@ -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"))

5
src/test/Makefile.in Normal file → Executable file
View File

@ -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

7
src/test/check_getdns_address_sync.h Normal file → Executable file
View File

@ -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;

19
src/test/check_getdns_common.c Normal file → Executable file
View File

@ -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
*/

14
src/test/check_getdns_common.h Normal file → Executable file
View File

@ -143,12 +143,26 @@
// 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
* a test may want to look at from the response.
*/
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.
*/

142
src/test/tests_namespaces.c Executable file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 */

379
src/test/tests_namespaces.good Executable file
View File

@ -0,0 +1,379 @@
The packet {
"canonical_name": <bindata of "localhost.">,
"just_address_answers":
[
{
"address_data": <bindata for 127.0.0.1>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for ::1>,
"address_type": <bindata of "IPv6">
}
],
"replies_full": [],
"replies_tree": [],
"status": GETDNS_RESPSTATUS_GOOD
}
The packet {
"answer_type": GETDNS_NAMETYPE_DNS,
"canonical_name": <bindata of "www.google.com.">,
"just_address_answers":
[
{
"address_data": <bindata for 74.125.24.104>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for 74.125.24.103>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for 74.125.24.105>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for 74.125.24.99>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for 74.125.24.147>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for 74.125.24.106>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for 2a00:1450:400b:c02::63>,
"address_type": <bindata of "IPv6">
}
],
"replies_full":
[
<bindata for \022\129\128\000\001\000\006\000\000\000\001\003www\006google\003com\000\000\001\000\001\003www\006google\003com\000\000\001\000\001\000\000\001,\000\004J}\024h\003www\006google\003com\000\000\001\000\001\000\000\001,\000\004J}\024g\003www\006google\003com\000\000\001\000\001\000\000\001,\000\004J}\024i\003www\006google\003com\000\000\001\000\001\000\000\001,\000\004J}\024c\003www\006google\003com\000\000\001\000\001\000\000\001,\000\004J}\024\147\003www\006google\003com\000\000\001\000\001\000\000\001,\000\004J}\024j\000\000\)\016\000\000.>,
<bindata of 0xe4e98180000100010000000103777777...>
],
"replies_tree":
[
{
"additional": [],
"answer":
[
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv4_address": <bindata for 74.125.24.104>,
"rdata_raw": <bindata of 0x4a7d1868>
},
"ttl": 300,
"type": GETDNS_RRTYPE_A
},
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv4_address": <bindata for 74.125.24.103>,
"rdata_raw": <bindata of 0x4a7d1867>
},
"ttl": 300,
"type": GETDNS_RRTYPE_A
},
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv4_address": <bindata for 74.125.24.105>,
"rdata_raw": <bindata of 0x4a7d1869>
},
"ttl": 300,
"type": GETDNS_RRTYPE_A
},
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv4_address": <bindata for 74.125.24.99>,
"rdata_raw": <bindata of 0x4a7d1863>
},
"ttl": 300,
"type": GETDNS_RRTYPE_A
},
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv4_address": <bindata for 74.125.24.147>,
"rdata_raw": <bindata of 0x4a7d1893>
},
"ttl": 300,
"type": GETDNS_RRTYPE_A
},
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv4_address": <bindata for 74.125.24.106>,
"rdata_raw": <bindata of 0x4a7d186a>
},
"ttl": 300,
"type": GETDNS_RRTYPE_A
}
],
"answer_type": GETDNS_NAMETYPE_DNS,
"authority": [],
"canonical_name": <bindata of "www.google.com.">,
"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": <bindata for www.google.com.>,
"qtype": GETDNS_RRTYPE_A
}
},
{
"additional": [],
"answer":
[
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for www.google.com.>,
"rdata":
{
"ipv6_address": <bindata for 2a00:1450:400b:c02::63>,
"rdata_raw": <bindata of 0x2a001450400b0c020000000000000063>
},
"ttl": 300,
"type": GETDNS_RRTYPE_AAAA
}
],
"answer_type": GETDNS_NAMETYPE_DNS,
"authority": [],
"canonical_name": <bindata of "www.google.com.">,
"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": <bindata for www.google.com.>,
"qtype": GETDNS_RRTYPE_AAAA
}
}
],
"status": GETDNS_RESPSTATUS_GOOD
}
The packet {
"answer_type": GETDNS_NAMETYPE_DNS,
"canonical_name": <bindata of "localhost.">,
"just_address_answers":
[
{
"address_data": <bindata for 127.0.0.1>,
"address_type": <bindata of "IPv4">
}
],
"replies_full":
[
<bindata of 0x55bf85800001000100000001096c6f63...>
],
"replies_tree":
[
{
"additional": [],
"answer":
[
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for localhost.>,
"rdata":
{
"ipv4_address": <bindata for 127.0.0.1>,
"rdata_raw": <bindata of 0x7f000001>
},
"ttl": 86400,
"type": GETDNS_RRTYPE_A
}
],
"answer_type": GETDNS_NAMETYPE_DNS,
"authority": [],
"canonical_name": <bindata of "localhost.">,
"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": <bindata for localhost.>,
"qtype": GETDNS_RRTYPE_A
}
}
],
"status": GETDNS_RESPSTATUS_GOOD
}
The packet {
"answer_type": GETDNS_NAMETYPE_DNS,
"canonical_name": <bindata of "localhost.">,
"just_address_answers":
[
{
"address_data": <bindata for 127.0.0.1>,
"address_type": <bindata of "IPv4">
},
{
"address_data": <bindata for ::1>,
"address_type": <bindata of "IPv6">
}
],
"replies_full":
[
<bindata of 0x8cbe85800001000100000001096c6f63...>,
<bindata of 0xa65485800001000100000001096c6f63...>
],
"replies_tree":
[
{
"additional": [],
"answer":
[
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for localhost.>,
"rdata":
{
"ipv4_address": <bindata for 127.0.0.1>,
"rdata_raw": <bindata of 0x7f000001>
},
"ttl": 86400,
"type": GETDNS_RRTYPE_A
}
],
"answer_type": GETDNS_NAMETYPE_DNS,
"authority": [],
"canonical_name": <bindata of "localhost.">,
"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": <bindata for localhost.>,
"qtype": GETDNS_RRTYPE_A
}
},
{
"additional": [],
"answer":
[
{
"class": GETDNS_RRCLASS_IN,
"name": <bindata for localhost.>,
"rdata":
{
"ipv6_address": <bindata for ::1>,
"rdata_raw": <bindata of 0x00000000000000000000000000000001>
},
"ttl": 10800,
"type": GETDNS_RRTYPE_AAAA
}
],
"answer_type": GETDNS_NAMETYPE_DNS,
"authority": [],
"canonical_name": <bindata of "localhost.">,
"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": <bindata for localhost.>,
"qtype": GETDNS_RRTYPE_AAAA
}
}
],
"status": GETDNS_RESPSTATUS_GOOD
}

74
src/util-internal.c Normal file → Executable file
View File

@ -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

2
src/util-internal.h Normal file → Executable file
View File

@ -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);