mirror of https://github.com/getdnsapi/getdns.git
Adding cancel and reply formatting
This commit is contained in:
parent
da8dad5913
commit
9c75239aaa
|
@ -822,6 +822,23 @@ getdns_extension_set_libevent_base(
|
|||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_extension_set_libevent_base */
|
||||
|
||||
/* cancel the request */
|
||||
static void cancel_dns_req(getdns_dns_req* req) {
|
||||
getdns_network_req* netreq = req->first_req;
|
||||
while (netreq) {
|
||||
if (netreq->state == NET_REQ_IN_FLIGHT) {
|
||||
/* for ev based ub, this should always prevent
|
||||
* the callback from firing */
|
||||
ub_cancel(req->unbound, netreq->unbound_id);
|
||||
netreq->state = NET_REQ_CANCELED;
|
||||
} else if (netreq->state == NET_REQ_NOT_SENT) {
|
||||
netreq->state = NET_REQ_CANCELED;
|
||||
}
|
||||
netreq = netreq->next;
|
||||
}
|
||||
req->canceled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* getdns_cancel_callback
|
||||
*
|
||||
|
@ -832,8 +849,35 @@ getdns_cancel_callback(
|
|||
getdns_transaction_t transaction_id
|
||||
)
|
||||
{
|
||||
UNUSED_PARAM(context);
|
||||
UNUSED_PARAM(transaction_id);
|
||||
getdns_dns_req *req = NULL;
|
||||
getdns_callback_t cb = NULL;
|
||||
void* user_pointer = NULL;
|
||||
|
||||
/* delete the node from the tree */
|
||||
ldns_rbnode_t* node = ldns_rbtree_delete(context->outbound_requests,
|
||||
&transaction_id);
|
||||
|
||||
if (!node) {
|
||||
return GETDNS_RETURN_UNKNOWN_TRANSACTION;
|
||||
}
|
||||
req = (getdns_dns_req*) node->data;
|
||||
/* do the cancel */
|
||||
|
||||
cancel_dns_req(req);
|
||||
cb = req->user_callback;
|
||||
user_pointer = req->user_pointer;
|
||||
|
||||
/* clean up */
|
||||
context->memory_deallocator(node);
|
||||
dns_req_free(req);
|
||||
|
||||
/* fire callback */
|
||||
cb(context,
|
||||
GETDNS_CALLBACK_CANCEL,
|
||||
NULL,
|
||||
user_pointer,
|
||||
transaction_id);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_cancel_callback */
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
*
|
||||
* /brief getdns core functions
|
||||
*
|
||||
*
|
||||
* This is the meat of the API
|
||||
* Originally taken from the getdns API description pseudo implementation.
|
||||
*
|
||||
|
@ -15,10 +15,10 @@
|
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include <getdns/getdns.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <util-internal.h>
|
||||
|
||||
/* stuff to make it compile pedantically */
|
||||
#define UNUSED_PARAM(x) ((void)(x))
|
||||
|
@ -62,7 +64,32 @@ char *
|
|||
getdns_display_ip_address(
|
||||
struct getdns_bindata *bindata_of_ipv4_or_ipv6_address
|
||||
)
|
||||
{ UNUSED_PARAM(bindata_of_ipv4_or_ipv6_address); return NULL; }
|
||||
{
|
||||
char buff[256];
|
||||
if (!bindata_of_ipv4_or_ipv6_address ||
|
||||
bindata_of_ipv4_or_ipv6_address->size == 0 ||
|
||||
!bindata_of_ipv4_or_ipv6_address->data) {
|
||||
return NULL;
|
||||
}
|
||||
if (bindata_of_ipv4_or_ipv6_address->size == 4) {
|
||||
const char* ipStr = inet_ntop(AF_INET,
|
||||
bindata_of_ipv4_or_ipv6_address->data,
|
||||
buff,
|
||||
256);
|
||||
if (ipStr) {
|
||||
return strdup(ipStr);
|
||||
}
|
||||
} else if (bindata_of_ipv4_or_ipv6_address->size == 16) {
|
||||
const char* ipStr = inet_ntop(AF_INET6,
|
||||
bindata_of_ipv4_or_ipv6_address->data,
|
||||
buff,
|
||||
256);
|
||||
if (ipStr) {
|
||||
return strdup(ipStr);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
getdns_strerror(getdns_return_t err, char *buf, size_t buflen)
|
||||
|
|
|
@ -106,28 +106,41 @@ static void handle_dns_request_complete(getdns_dns_req* dns_req) {
|
|||
/* clean up the request */
|
||||
getdns_context_clear_outbound_request(dns_req);
|
||||
dns_req_free(dns_req);
|
||||
if (response) {
|
||||
cb(context,
|
||||
GETDNS_CALLBACK_COMPLETE,
|
||||
response,
|
||||
user_arg,
|
||||
trans_id);
|
||||
} else {
|
||||
cb(context,
|
||||
GETDNS_CALLBACK_ERROR,
|
||||
NULL,
|
||||
user_arg,
|
||||
trans_id);
|
||||
}
|
||||
|
||||
cb(context,
|
||||
GETDNS_CALLBACK_COMPLETE,
|
||||
response,
|
||||
user_arg,
|
||||
trans_id);
|
||||
}
|
||||
|
||||
static int submit_network_request(getdns_network_req* netreq) {
|
||||
getdns_dns_req *dns_req = netreq->owner;
|
||||
netreq->state = NET_REQ_IN_FLIGHT;
|
||||
return ub_resolve_event(dns_req->unbound,
|
||||
int r = ub_resolve_event(dns_req->unbound,
|
||||
dns_req->name,
|
||||
netreq->request_type,
|
||||
netreq->request_class,
|
||||
netreq,
|
||||
ub_resolve_callback,
|
||||
&(netreq->unbound_id));
|
||||
netreq->state = NET_REQ_IN_FLIGHT;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus) {
|
||||
getdns_network_req* netreq = (getdns_network_req*) arg;
|
||||
/* if netreq->state == NET_REQ_NOT_SENT here, that implies
|
||||
* that ub called us back immediately - probably from a local file.
|
||||
* This most likely means that getdns_general has not returned
|
||||
*/
|
||||
netreq->state = NET_REQ_FINISHED;
|
||||
if (err) {
|
||||
handle_network_request_error(netreq, err);
|
||||
|
@ -153,13 +166,13 @@ static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec
|
|||
|
||||
getdns_return_t
|
||||
getdns_general_ub(struct ub_ctx* unbound,
|
||||
getdns_context_t context,
|
||||
const char *name,
|
||||
uint16_t request_type,
|
||||
struct getdns_dict *extensions,
|
||||
void *userarg,
|
||||
getdns_transaction_t *transaction_id,
|
||||
getdns_callback_t callbackfn) {
|
||||
getdns_context_t context,
|
||||
const char *name,
|
||||
uint16_t request_type,
|
||||
struct getdns_dict *extensions,
|
||||
void *userarg,
|
||||
getdns_transaction_t *transaction_id,
|
||||
getdns_callback_t callbackfn) {
|
||||
|
||||
getdns_return_t gr;
|
||||
int r;
|
||||
|
@ -182,10 +195,6 @@ getdns_general_ub(struct ub_ctx* unbound,
|
|||
req->user_pointer = userarg;
|
||||
req->user_callback = callbackfn;
|
||||
|
||||
/* TODO:
|
||||
handle immediate callback
|
||||
*/
|
||||
|
||||
if (transaction_id) {
|
||||
*transaction_id = req->trans_id;
|
||||
}
|
||||
|
@ -221,7 +230,7 @@ getdns_general_ub(struct ub_ctx* unbound,
|
|||
/* Can't do async without an event loop
|
||||
* or callback
|
||||
*/
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
return getdns_general_ub(context->unbound_async,
|
||||
|
|
|
@ -252,6 +252,38 @@ struct event_base;
|
|||
#define GETDNS_STR_PORT "port"
|
||||
#define GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6 "return_both_v4_and_v6"
|
||||
|
||||
#define GETDNS_STR_KEY_STATUS "status"
|
||||
#define GETDNS_STR_KEY_REPLIES_TREE "replies_tree"
|
||||
#define GETDNS_STR_KEY_REPLIES_FULL "replies_full"
|
||||
#define GETDNS_STR_KEY_JUST_ADDRS "just_address_answers"
|
||||
#define GETDNS_STR_KEY_CANONICAL_NM "canonical_name"
|
||||
#define GETDNS_STR_KEY_ANSWER_TYPE "answer_type"
|
||||
#define GETDNS_STR_KEY_INTERM_ALIASES "intermediate_aliases"
|
||||
#define GETDNS_STR_KEY_NAME "name"
|
||||
#define GETDNS_STR_KEY_HEADER "header"
|
||||
#define GETDNS_STR_KEY_QUESTION "question"
|
||||
#define GETDNS_STR_KEY_ANSWER "answer"
|
||||
#define GETDNS_STR_KEY_ID "id"
|
||||
#define GETDNS_STR_KEY_QR "qr"
|
||||
#define GETDNS_STR_KEY_OPC "opcode"
|
||||
#define GETDNS_STR_KEY_TYPE "type"
|
||||
#define GETDNS_STR_KEY_CLASS "class"
|
||||
#define GETDNS_STR_KEY_TTL "ttl"
|
||||
#define GETDNS_STR_KEY_RDATA "rdata"
|
||||
#define GETDNS_STR_KEY_V4_ADDR "ipv4_address"
|
||||
#define GETDNS_STR_KEY_V6_ADDR "ipv6_address"
|
||||
#define GETDNS_STR_KEY_RDATA_RAW "rdata_raw"
|
||||
#define GETDNS_STR_KEY_AUTHORITY "authority"
|
||||
#define GETDNS_STR_KEY_ADDITIONAL "additional"
|
||||
#define GETDNS_STR_KEY_QTYPE "qtype"
|
||||
#define GETDNS_STR_KEY_QCLASS "qclass"
|
||||
#define GETDNS_STR_KEY_QNAME "qname"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "types-internal.h"
|
||||
#include "util-internal.h"
|
||||
#include <unbound.h>
|
||||
|
||||
/* useful macros */
|
||||
#define gd_malloc(sz) context->memory_allocator(sz)
|
||||
|
@ -111,6 +112,7 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
|
|||
result->name = strdup(name);
|
||||
result->context = context;
|
||||
result->unbound = unbound;
|
||||
result->canceled = 0;
|
||||
result->current_req = NULL;
|
||||
result->first_req = NULL;
|
||||
result->trans_id = ldns_get_random();
|
||||
|
|
16
src/sync.c
16
src/sync.c
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
*
|
||||
* /brief getdns core functions for synchronous use
|
||||
*
|
||||
*
|
||||
* Originally taken from the getdns API description pseudo implementation.
|
||||
*
|
||||
*/
|
||||
|
@ -14,10 +14,10 @@
|
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
@ -58,7 +58,7 @@ static void sync_callback_func(getdns_context_t context,
|
|||
|
||||
static void * request_thread_start(void *arg) {
|
||||
struct sync_request_data *req_data = arg;
|
||||
|
||||
|
||||
req_data->response_status = getdns_general_ub(req_data->context->unbound_sync,
|
||||
req_data->context,
|
||||
req_data->name,
|
||||
|
@ -67,7 +67,7 @@ static void * request_thread_start(void *arg) {
|
|||
req_data,
|
||||
NULL,
|
||||
sync_callback_func);
|
||||
|
||||
|
||||
event_base_dispatch(req_data->context->event_base_sync);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ getdns_general_sync(
|
|||
GETDNS_RETURN_GOOD,
|
||||
response
|
||||
};
|
||||
|
||||
|
||||
/* create the thread */
|
||||
int ret = pthread_attr_init(&attr);
|
||||
if (ret != 0) {
|
||||
|
@ -133,7 +133,7 @@ getdns_address_sync(
|
|||
getdns_dict_set_int(extensions,
|
||||
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_length, response);
|
||||
|
@ -163,7 +163,7 @@ getdns_service_sync(
|
|||
struct getdns_dict **response
|
||||
)
|
||||
{
|
||||
|
||||
|
||||
return getdns_general_sync(context, name, GETDNS_RRTYPE_SRV, extensions,
|
||||
response_length, response);
|
||||
|
||||
|
|
|
@ -42,14 +42,10 @@ void this_callbackfn(struct getdns_context_t *this_context,
|
|||
{
|
||||
if (this_callback_type == GETDNS_CALLBACK_COMPLETE) /* This is a callback with data */
|
||||
{
|
||||
getdns_bindata* bindata = NULL;
|
||||
getdns_dict_get_bindata(this_response, "pkt", &bindata);
|
||||
if (bindata) {
|
||||
char* data = (char*) bindata->data;
|
||||
data[bindata->size] = 0;
|
||||
memcpy(data, bindata->data, bindata->size);
|
||||
fprintf(stdout, "The packet %s\n", data);
|
||||
}
|
||||
char* res = getdns_pretty_print_dict(this_response);
|
||||
fprintf(stdout, "%s", res);
|
||||
getdns_dict_destroy(this_response);
|
||||
|
||||
}
|
||||
else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
|
||||
fprintf(stderr, "The callback with ID %lld was cancelled. Exiting.", this_transaction_id);
|
||||
|
@ -82,7 +78,7 @@ main()
|
|||
const char * this_name = "www.google.com";
|
||||
char* this_userarg = "somestring"; // Could add things here to help identify this call
|
||||
getdns_transaction_t this_transaction_id = 0;
|
||||
|
||||
|
||||
/* Make the call */
|
||||
getdns_return_t dns_request_return = getdns_address(this_context, this_name,
|
||||
NULL, this_userarg, &this_transaction_id, this_callbackfn);
|
||||
|
|
|
@ -42,7 +42,8 @@ struct ub_ctx;
|
|||
typedef enum network_req_state_enum {
|
||||
NET_REQ_NOT_SENT,
|
||||
NET_REQ_IN_FLIGHT,
|
||||
NET_REQ_FINISHED
|
||||
NET_REQ_FINISHED,
|
||||
NET_REQ_CANCELED
|
||||
} network_req_state;
|
||||
|
||||
/**
|
||||
|
@ -77,6 +78,9 @@ typedef struct getdns_dns_req {
|
|||
/* name */
|
||||
char *name;
|
||||
|
||||
/* canceled flag */
|
||||
int canceled;
|
||||
|
||||
/* current network request */
|
||||
struct getdns_network_req *current_req;
|
||||
|
||||
|
@ -96,7 +100,8 @@ typedef struct getdns_dns_req {
|
|||
getdns_callback_t user_callback;
|
||||
void *user_pointer;
|
||||
|
||||
getdns_transaction_t trans_id; /* the transaction id */
|
||||
/* the transaction id */
|
||||
getdns_transaction_t trans_id;
|
||||
|
||||
} getdns_dns_req;
|
||||
|
||||
|
@ -121,7 +126,4 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
|
|||
|
||||
void dns_req_free(getdns_dns_req* req);
|
||||
|
||||
/* cancel the request */
|
||||
getdns_return_t dns_req_cancel(getdns_dns_req* req);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
|
||||
const char* value) {
|
||||
/* account for the null term */
|
||||
if (value == NULL) {
|
||||
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
|
||||
}
|
||||
getdns_bindata type_bin = { strlen(value) + 1, (uint8_t*) value };
|
||||
return getdns_dict_set_bindata(dict, name, &type_bin);
|
||||
}
|
||||
|
@ -114,15 +117,336 @@ getdns_return_t sockaddr_to_dict(struct sockaddr_storage* address, getdns_dict**
|
|||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_dict *create_getdns_response(struct getdns_dns_req* completed_request) {
|
||||
ldns_pkt* pkt = completed_request->first_req->result;
|
||||
char* data = ldns_pkt2str(pkt);
|
||||
/* result must be freed */
|
||||
static char* convert_rdf_to_str(ldns_rdf* rdf) {
|
||||
if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
|
||||
ldns_dname2canonical(rdf);
|
||||
}
|
||||
return ldns_rdf2str(rdf);
|
||||
}
|
||||
|
||||
/* create the header dict */
|
||||
static getdns_dict *create_reply_header_dict(ldns_pkt* reply) {
|
||||
/* { "id": 23456, "qr": 1, "opcode": 0, ... }, */
|
||||
int r = 0;
|
||||
getdns_dict* result = getdns_dict_create();
|
||||
getdns_bindata bindata = {
|
||||
strlen(data), (uint8_t*) data
|
||||
};
|
||||
getdns_dict_set_bindata(result, "pkt", &bindata);
|
||||
free(data);
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
/* cheat since we know GETDNS_RETURN_GOOD == 0 */
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_ID, ldns_pkt_id(reply));
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_QR, ldns_pkt_qr(reply));
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_OPC, (int) ldns_pkt_get_opcode(reply));
|
||||
|
||||
if (r != 0) {
|
||||
getdns_dict_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static getdns_dict *create_reply_question_dict(ldns_pkt* reply) {
|
||||
/* { "qname": <bindata for "www.example.com">, "qtype": 1, "qclass": 1 } */
|
||||
int r = 0;
|
||||
ldns_rr *question = NULL;
|
||||
char* qname;
|
||||
getdns_dict* result = getdns_dict_create();
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
question = ldns_rr_list_rr(ldns_pkt_question(reply), 0);
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_QTYPE, (int) ldns_rr_get_type(question));
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_QCLASS, (int) ldns_rr_get_class(question));
|
||||
qname = convert_rdf_to_str(ldns_rr_owner(question));
|
||||
if (qname) {
|
||||
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_QNAME, qname);
|
||||
free(qname);
|
||||
} else {
|
||||
r = 1;
|
||||
}
|
||||
if (r != 0) {
|
||||
getdns_dict_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static getdns_dict *create_dict_from_rdf(ldns_rdf* rdf) {
|
||||
/*
|
||||
create a dict w/ rdata_raw and special fields if needed
|
||||
i.e.
|
||||
{
|
||||
"ipv4_address": <bindata of 0x0a0b0c01>
|
||||
"rdata_raw": <bindata of 0x0a0b0c01>
|
||||
}
|
||||
*/
|
||||
int r = 0;
|
||||
getdns_bindata rbin = { ldns_rdf_size(rdf), ldns_rdf_data(rdf) };
|
||||
getdns_dict* result = getdns_dict_create();
|
||||
r |= getdns_dict_set_bindata(result, GETDNS_STR_KEY_RDATA_RAW, &rbin);
|
||||
if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_AAAA) {
|
||||
r |= getdns_dict_set_bindata(result, GETDNS_STR_KEY_V6_ADDR, &rbin);
|
||||
} else if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_A) {
|
||||
r |= getdns_dict_set_bindata(result, GETDNS_STR_KEY_V4_ADDR, &rbin);
|
||||
}
|
||||
if (r != 0) {
|
||||
getdns_dict_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static getdns_dict *create_dict_from_rr(ldns_rr* rr) {
|
||||
/*
|
||||
{
|
||||
"name": <bindata for "www.example.com">,
|
||||
"type": 1,
|
||||
"class": 1,
|
||||
"ttl": 33000,
|
||||
"rdata":
|
||||
{
|
||||
"ipv4_address": <bindata of 0x0a0b0c01>
|
||||
"rdata_raw": <bindata of 0x0a0b0c01>
|
||||
}
|
||||
}
|
||||
*/
|
||||
int r = 0;
|
||||
char * name = NULL;
|
||||
getdns_dict *result = getdns_dict_create();
|
||||
size_t rd_count = ldns_rr_rd_count(rr);
|
||||
ldns_rdf* owner = ldns_rr_owner(rr);
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_TYPE, (int) ldns_rr_get_type(rr));
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_CLASS, (int) ldns_rr_get_class(rr));
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_TTL, ldns_rr_ttl(rr));
|
||||
if (owner) {
|
||||
name = convert_rdf_to_str(owner);
|
||||
if (name) {
|
||||
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_NAME, name);
|
||||
free(name);
|
||||
} else {
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
/* create rdatas */
|
||||
if (rd_count >= 1) {
|
||||
getdns_dict* rdata = create_dict_from_rdf(ldns_rr_rdf(rr, 0));
|
||||
r |= getdns_dict_set_dict(result, GETDNS_STR_KEY_RDATA, rdata);
|
||||
}
|
||||
/* TODO - if more than one, is rdata a list? */
|
||||
|
||||
if (r != 0) {
|
||||
getdns_dict_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* helper to convert an rr_list to getdns_list.
|
||||
returns a list of objects where each object
|
||||
is a result from create_dict_from_rr */
|
||||
static getdns_list *create_list_from_rr_list(ldns_rr_list* rr_list) {
|
||||
size_t i = 0;
|
||||
size_t idx = 0;
|
||||
int r = 0;
|
||||
getdns_list *result = getdns_list_create();
|
||||
for (i = 0; i < ldns_rr_list_rr_count(rr_list); ++i) {
|
||||
ldns_rr *rr = ldns_rr_list_rr(rr_list, i);
|
||||
r |= getdns_list_add_item(result, &idx);
|
||||
r |= getdns_list_set_dict(result, idx, create_dict_from_rr(rr));
|
||||
}
|
||||
if (r != 0) {
|
||||
getdns_list_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* helper to add the ipv4 or ipv6 bin data to the list of addrs */
|
||||
static getdns_return_t add_only_addresses(getdns_list* addrs, ldns_rr_list* rr_list) {
|
||||
int r = 0;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < ldns_rr_list_rr_count(rr_list); ++i) {
|
||||
ldns_rr *rr = ldns_rr_list_rr(rr_list, i);
|
||||
size_t j = 0;
|
||||
size_t rd_count = ldns_rr_rd_count(rr);
|
||||
for (j = 0; j < rd_count; ++j) {
|
||||
size_t item_idx = 0;
|
||||
ldns_rdf* rdf = ldns_rr_rdf(rr, j);
|
||||
getdns_bindata rbin = { ldns_rdf_size(rdf), ldns_rdf_data(rdf) };
|
||||
r |= getdns_list_add_item(addrs, &item_idx);
|
||||
r |= getdns_list_set_bindata(addrs, item_idx, &rbin);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static getdns_dict *create_reply_dict(getdns_network_req* req,
|
||||
getdns_list *just_addrs) {
|
||||
/* turn a packet into this glorious structure
|
||||
|
||||
{ # This is the first reply
|
||||
"header": { "id": 23456, "qr": 1, "opcode": 0, ... },
|
||||
"question": { "qname": <bindata for "www.example.com">, "qtype": 1, "qclass": 1 },
|
||||
"answer":
|
||||
[
|
||||
{
|
||||
"name": <bindata for "www.example.com">,
|
||||
"type": 1,
|
||||
"class": 1,
|
||||
"ttl": 33000,
|
||||
"rdata":
|
||||
{
|
||||
"ipv4_address": <bindata of 0x0a0b0c01>
|
||||
"rdata_raw": <bindata of 0x0a0b0c01>
|
||||
}
|
||||
}
|
||||
],
|
||||
"authority":
|
||||
[
|
||||
{
|
||||
"name": <bindata for "ns1.example.com">,
|
||||
"type": 1,
|
||||
"class": 1,
|
||||
"ttl": 600,
|
||||
"rdata":
|
||||
{
|
||||
"ipv4_address": <bindata of 0x65439876>
|
||||
"rdata_raw": <bindata of 0x65439876>
|
||||
}
|
||||
}
|
||||
]
|
||||
"additional": [],
|
||||
"canonical_name": <bindata for "www.example.com">,
|
||||
"answer_type": GETDNS_NAMETYPE_DNS
|
||||
}
|
||||
|
||||
*/
|
||||
int r = 0;
|
||||
ldns_pkt *reply = req->result;
|
||||
ldns_rr_list *rr_list = NULL;
|
||||
ldns_rr* question = NULL;
|
||||
getdns_dict *subdict = NULL;
|
||||
getdns_list *sublist = NULL;
|
||||
char* name = NULL;
|
||||
|
||||
getdns_dict *result = getdns_dict_create();
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
/* header */
|
||||
subdict = create_reply_header_dict(reply);
|
||||
r |= getdns_dict_set_dict(result, GETDNS_STR_KEY_HEADER, subdict);
|
||||
getdns_dict_destroy(subdict);
|
||||
|
||||
/* question */
|
||||
subdict = create_reply_question_dict(reply);
|
||||
r |= getdns_dict_set_dict(result, GETDNS_STR_KEY_QUESTION, subdict);
|
||||
getdns_dict_destroy(subdict);
|
||||
|
||||
/* answers */
|
||||
rr_list = ldns_pkt_answer(reply);
|
||||
sublist = create_list_from_rr_list(rr_list);
|
||||
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_ANSWER, sublist);
|
||||
getdns_list_destroy(sublist);
|
||||
if ((req->request_type == GETDNS_RRTYPE_A ||
|
||||
req->request_type == GETDNS_RRTYPE_AAAA) &&
|
||||
just_addrs != NULL) {
|
||||
/* add to just addrs */
|
||||
r |= add_only_addresses(just_addrs, rr_list);
|
||||
}
|
||||
|
||||
/* authority */
|
||||
rr_list = ldns_pkt_authority(reply);
|
||||
sublist = create_list_from_rr_list(rr_list);
|
||||
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_AUTHORITY, sublist);
|
||||
getdns_list_destroy(sublist);
|
||||
|
||||
/* additional */
|
||||
rr_list = ldns_pkt_additional(reply);
|
||||
sublist = create_list_from_rr_list(rr_list);
|
||||
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_ADDITIONAL, sublist);
|
||||
getdns_list_destroy(sublist);
|
||||
|
||||
/* other stuff */
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_ANSWER_TYPE, GETDNS_NAMETYPE_DNS);
|
||||
question = ldns_rr_list_rr(ldns_pkt_question(reply), 0);
|
||||
name = convert_rdf_to_str(ldns_rr_owner(question));
|
||||
if (name) {
|
||||
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM, name);
|
||||
free(name);
|
||||
} else {
|
||||
r |= 1;
|
||||
}
|
||||
if (r != 0) {
|
||||
getdns_dict_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* get_canonical_name(const char* name) {
|
||||
ldns_rdf* rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, name);
|
||||
if (!rdf) {
|
||||
return NULL;
|
||||
}
|
||||
char* result = convert_rdf_to_str(rdf);
|
||||
ldns_rdf_free(rdf);
|
||||
return result;
|
||||
}
|
||||
|
||||
getdns_dict *create_getdns_response(struct getdns_dns_req* completed_request) {
|
||||
getdns_dict* result = getdns_dict_create();
|
||||
getdns_list* replies_full = getdns_list_create();
|
||||
getdns_list* just_addrs = NULL;
|
||||
getdns_list* replies_tree = getdns_list_create();
|
||||
getdns_network_req *netreq = completed_request->first_req;
|
||||
|
||||
|
||||
int r = 0;
|
||||
|
||||
if (completed_request->first_req->request_class == GETDNS_RRTYPE_A ||
|
||||
completed_request->first_req->request_class == GETDNS_RRTYPE_AAAA) {
|
||||
just_addrs = getdns_list_create();
|
||||
}
|
||||
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS, GETDNS_RESPSTATUS_GOOD);
|
||||
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM, get_canonical_name(completed_request->name));
|
||||
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_ANSWER_TYPE, GETDNS_NAMETYPE_DNS);
|
||||
|
||||
while (netreq) {
|
||||
getdns_bindata full_data;
|
||||
full_data.data = NULL;
|
||||
full_data.size = 0;
|
||||
ldns_pkt *pkt = netreq->result;
|
||||
ldns_status s = ldns_pkt2wire(&(full_data.data), pkt, &(full_data.size));
|
||||
size_t idx = 0;
|
||||
/* reply tree */
|
||||
getdns_dict *reply = create_reply_dict(netreq, just_addrs);
|
||||
r |= getdns_list_add_item(replies_tree, &idx);
|
||||
r |= getdns_list_set_dict(replies_tree, idx, reply);
|
||||
/* buffer */
|
||||
if (s == LDNS_STATUS_OK) {
|
||||
r |= getdns_list_add_item(replies_full, &idx);
|
||||
r |= getdns_list_set_bindata(replies_full, idx, &full_data);
|
||||
free(full_data.data);
|
||||
} else {
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
netreq = netreq->next;
|
||||
}
|
||||
|
||||
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_REPLIES_TREE, replies_tree);
|
||||
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_REPLIES_FULL, replies_full);
|
||||
if (just_addrs) {
|
||||
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_JUST_ADDRS, just_addrs);
|
||||
}
|
||||
|
||||
if (r != 0) {
|
||||
getdns_dict_destroy(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue