Start with rdf iterators to rdata dict conversion

Todo:  OPT
This commit is contained in:
Willem Toorop 2015-02-17 11:53:01 +01:00
parent fd9ead4fec
commit ced873a80d
1 changed files with 291 additions and 95 deletions

View File

@ -311,9 +311,209 @@ add_only_addresses(struct getdns_list * addrs, ldns_rr_list * rr_list)
return r;
}
static struct getdns_dict *
create_reply_dict(struct getdns_context *context, getdns_network_req * req,
struct getdns_list * just_addrs)
getdns_dict *
priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
{
getdns_dict *rr_dict, *rdata_dict;
getdns_bindata bindata;
uint32_t int_val = 0;
getdns_data_type val_type;
priv_getdns_rdf_iter rdf_storage, *rdf;
getdns_list *repeat_list = NULL;
getdns_dict *repeat_dict = NULL;
assert(context);
assert(i);
if (!(rr_dict = getdns_dict_create_with_context(context)))
return NULL;
bindata.size = i->rr_type - i->pos;
bindata.data = i->pos;
/* question */
if (priv_getdns_rr_iter_section(i) == GLDNS_SECTION_QUESTION) {
if (getdns_dict_set_int(rr_dict, "qtype",
(uint32_t) gldns_read_uint16(i->rr_type)) ||
getdns_dict_set_int(rr_dict, "qclass",
(uint32_t) gldns_read_uint16(i->rr_type + 2)) ||
getdns_dict_set_bindata(rr_dict, "qname", &bindata)) {
goto error;
}
return rr_dict;
}
if (getdns_dict_set_int(rr_dict, "type",
(uint32_t) gldns_read_uint16(i->rr_type)) ||
getdns_dict_set_int(rr_dict, "class",
(uint32_t) gldns_read_uint16(i->rr_type + 2)) ||
getdns_dict_set_int(rr_dict, "ttl",
(uint32_t) gldns_read_uint32(i->rr_type + 4)) ||
getdns_dict_set_bindata(rr_dict, "name", &bindata)) {
goto error;
}
if (!(rdata_dict = getdns_dict_create_with_context(context)))
goto error;
if ((rdf = priv_getdns_rdf_iter_init(&rdf_storage, i))) {
bindata.size = rdf->end - rdf->pos;
bindata.data = rdf->pos;
if (getdns_dict_set_bindata(rdata_dict, "rdata_raw", &bindata))
goto rdata_error;
}
for (; rdf; rdf = priv_getdns_rdf_iter_next(rdf)) {
if (rdf->rdd_pos->type & GETDNS_RDF_INTEGER) {
val_type = t_int;
switch (rdf->rdd_pos->type & GETDNS_RDF_FIXEDSZ) {
case 1: if (getdns_dict_set_int(rdata_dict,
rdf->rdd_pos->name, (uint32_t)*rdf->pos))
goto rdata_error;
break;
case 2: if (getdns_dict_set_int(rdata_dict,
rdf->rdd_pos->name, (uint32_t)
gldns_read_uint16(rdf->pos)))
goto rdata_error;
break;
case 4: if (getdns_dict_set_int(rdata_dict,
rdf->rdd_pos->name, (uint32_t)
gldns_read_uint32(rdf->pos)))
goto rdata_error;
break;
default:
break;
}
} else if (rdf->rdd_pos->type & GETDNS_RDF_BINDATA) {
val_type = t_bindata;
if (rdf->rdd_pos->type & GETDNS_RDF_FIXEDSZ) {
bindata.size = rdf->rdd_pos->type
& GETDNS_RDF_FIXEDSZ;
bindata.data = rdf->pos;
} else switch(rdf->rdd_pos->type & GETDNS_RDF_LEN_VAL){
case 0x100:
bindata.size = *rdf->pos;
bindata.data = rdf->pos + 1;
break;
case 0x200:
bindata.size = gldns_read_uint16(rdf->pos);
bindata.data = rdf->pos + 2;
break;
default:
bindata.size = rdf->nxt - rdf->pos;
bindata.data = rdf->pos;
break;
}
} else
assert(0);
if (! rdf->rdd_repeat) {
switch (val_type) {
case t_int:
if (getdns_dict_set_int(rdata_dict,
rdf->rdd_pos->name, int_val))
goto rdata_error;
break;
case t_bindata:
if (getdns_dict_set_bindata(rdata_dict,
rdf->rdd_pos->name, &bindata))
goto rdata_error;
break;
default:
break;
}
continue;
} else if (rdf->rdd_pos == rdf->rdd_repeat) {
/* list with rdf values */
if (! repeat_list && !(repeat_list =
getdns_list_create_with_context(context)))
goto rdata_error;
switch (val_type) {
case t_int:
if (getdns_list_append_int(repeat_list,
int_val))
goto rdata_error;
break;
case t_bindata:
if (getdns_list_append_bindata(repeat_list,
&bindata))
goto rdata_error;
break;
default:
break;
}
continue;
}
/* list with dicts with rdf values */
if (rdf->rdd_pos == rdf->rdd_repeat + 1) {
if (repeat_dict) {
if (getdns_list_append_dict(
repeat_list, repeat_dict))
goto rdata_error;
getdns_dict_destroy(repeat_dict);
repeat_dict = NULL;
}
if (!(repeat_dict =
getdns_dict_create_with_context(context)))
goto rdata_error;
}
assert(repeat_dict);
switch (val_type) {
case t_int:
if (getdns_dict_set_int(repeat_dict,
rdf->rdd_pos->name, int_val))
goto rdata_error;
break;
case t_bindata:
if (getdns_dict_set_bindata(repeat_dict,
rdf->rdd_pos->name, &bindata))
goto rdata_error;
break;
default:
break;
}
}
if (repeat_dict) {
if (getdns_list_append_dict(repeat_list, repeat_dict))
goto rdata_error;
getdns_dict_destroy(repeat_dict);
repeat_dict = NULL;
}
if (repeat_list) {
if (getdns_dict_set_list(rdata_dict,
rdf_storage.rdd_repeat->name, repeat_list))
goto rdata_error;
getdns_list_destroy(repeat_list);
repeat_list = NULL;
}
if (getdns_dict_set_dict(rr_dict, "rdata", rdata_dict))
goto rdata_error;
return rr_dict;
rdata_error:
getdns_list_destroy(repeat_list);
getdns_dict_destroy(repeat_dict);
getdns_dict_destroy(rdata_dict);
error:
getdns_dict_destroy(rr_dict);
return NULL;
}
static getdns_dict *
create_reply_dict(getdns_context *context, getdns_network_req *req,
getdns_list *just_addrs)
{
/* turn a packet into this glorious structure
*
@ -354,108 +554,105 @@ create_reply_dict(struct getdns_context *context, getdns_network_req * req,
* }
*
*/
getdns_return_t r = 0;
ldns_pkt *reply = req->result;
ldns_rr_list *rr_list = NULL;
ldns_rr *question = NULL;
struct getdns_dict *subdict = NULL;
struct getdns_list *sublist = NULL;
char *name = NULL;
getdns_return_t r = GETDNS_RETURN_GOOD;
getdns_dict *result = getdns_dict_create_with_context(context);
getdns_dict *question = NULL;
getdns_list *sections[4] = { NULL
, getdns_list_create_with_context(context)
, getdns_list_create_with_context(context)
, getdns_list_create_with_context(context)
};
getdns_dict *rr_dict = NULL;
priv_getdns_rr_iter rr_iter_storage, *rr_iter;
priv_getdns_rdf_iter rdf_iter_storage, *rdf_iter;
getdns_bindata bindata;
gldns_pkt_section section;
struct getdns_dict *result = getdns_dict_create_with_context(context);
if (!result) {
return NULL;
}
if (!result)
goto error;
/* header */
do {
subdict = create_reply_header_dict(context, req);
r = getdns_dict_set_dict(result, GETDNS_STR_KEY_HEADER, subdict);
getdns_dict_destroy(subdict);
if (r != GETDNS_RETURN_GOOD) {
break;
}
if ((r = getdns_dict_set_dict(result, GETDNS_STR_KEY_HEADER,
create_reply_header_dict(context, req))))
goto error;
/* question */
r = priv_getdns_create_reply_question_dict(context, reply, &subdict);
if (r != GETDNS_RETURN_GOOD) {
break;
}
r = getdns_dict_set_dict(result, GETDNS_STR_KEY_QUESTION, subdict);
getdns_dict_destroy(subdict);
if (r != GETDNS_RETURN_GOOD) {
break;
}
/* answers */
rr_list = ldns_pkt_answer(reply);
sublist = create_list_from_rr_list(context, rr_list);
for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage
, req->response
, req->response_len)
; rr_iter
; rr_iter = priv_getdns_rr_iter_next(rr_iter)) {
r = getdns_dict_set_list(result, GETDNS_STR_KEY_ANSWER, sublist);
getdns_list_destroy(sublist);
if (r != GETDNS_RETURN_GOOD) {
break;
}
if (!(rr_dict = priv_getdns_rr_iter2rr_dict(context, rr_iter)))
continue;
if ((req->request_type == GETDNS_RRTYPE_A ||
req->request_type == GETDNS_RRTYPE_AAAA)) {
/* add to just addrs */
r = add_only_addresses(just_addrs, rr_list);
if (r != GETDNS_RETURN_GOOD) {
break;
}
}
section = priv_getdns_rr_iter_section(rr_iter);
if (section == GLDNS_SECTION_QUESTION) {
/* authority */
rr_list = ldns_pkt_authority(reply);
sublist = create_list_from_rr_list(context, rr_list);
r = getdns_dict_set_list(result, GETDNS_STR_KEY_AUTHORITY, sublist);
getdns_list_destroy(sublist);
if (r != GETDNS_RETURN_GOOD) {
break;
}
if (getdns_dict_set_dict(result, "question", rr_dict))
goto error;
continue;
}
if (getdns_list_append_dict(sections[section], rr_dict))
goto error;
/* additional */
rr_list = ldns_pkt_additional(reply);
sublist = create_list_from_rr_list(context, rr_list);
if (sublist) {
r |= priv_getdns_append_opt_rr(context, sublist, reply);
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_ADDITIONAL, sublist);
getdns_list_destroy(sublist);
if (r != GETDNS_RETURN_GOOD) {
break;
}
}
rr_dict = NULL;
/* other stuff
if (section != GLDNS_SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr_iter->rr_type) != GETDNS_RRTYPE_A &&
gldns_read_uint16(rr_iter->rr_type) != GETDNS_RRTYPE_AAAA)
continue;
if (!(rdf_iter = priv_getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
bindata.size = rdf_iter->nxt - rdf_iter->pos;
bindata.data = rdf_iter->pos;
if (!(rr_dict = getdns_dict_create_with_context(context)) ||
getdns_dict_set_bindata(rr_dict, "address_type",
gldns_read_uint16(rr_iter->rr_type) == GETDNS_RRTYPE_A ?
&IPv4_str_bindata : &IPv6_str_bindata) ||
getdns_dict_set_bindata(rr_dict, "address_data",&bindata)||
getdns_list_append_dict(just_addrs, rr_dict)) {
goto error;
}
getdns_dict_destroy(rr_dict);
rr_dict = NULL;
}
if (getdns_dict_set_list(result, "answer",
sections[GLDNS_SECTION_ANSWER]) ||
getdns_dict_set_list(result, "authority",
sections[GLDNS_SECTION_AUTHORITY]) ||
getdns_dict_set_list(result, "additional",
sections[GLDNS_SECTION_ADDITIONAL])) {
goto error;
}
/* other stuff
* Note that spec doesn't explicitely mention these.
* They are only showcased in the response dict example */
r = getdns_dict_set_int(result, GETDNS_STR_KEY_ANSWER_TYPE,
GETDNS_NAMETYPE_DNS);
if (r != GETDNS_RETURN_GOOD) {
break;
}
question = ldns_rr_list_rr(ldns_pkt_question(reply), 0);
/* Some packets (like with rcode REFUSED)
* don't even have RRs in the question section! */
if (question) {
name = convert_rdf_to_str(ldns_rr_owner(question));
if (! name) {
r = GETDNS_RETURN_MEMORY_ERROR;
break;
}
r = getdns_dict_util_set_string(result,
GETDNS_STR_KEY_CANONICAL_NM, name);
free(name);
}
} while (0);
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
if (getdns_dict_set_int(result, "answer_type", GETDNS_NAMETYPE_DNS))
goto error;
return result;
error:
getdns_dict_destroy(rr_dict);
getdns_list_destroy(sections[3]);
getdns_list_destroy(sections[2]);
getdns_list_destroy(sections[1]);
getdns_dict_destroy(question);
getdns_dict_destroy(result);
return NULL;
}
static char *
@ -516,7 +713,6 @@ create_getdns_response(getdns_dns_req *completed_request)
; ! r && (netreq = *netreq_p)
; netreq_p++) {
assert(! netreq->result);
if (! netreq->response_len)
continue;
@ -593,7 +789,7 @@ create_getdns_response(getdns_dns_req *completed_request)
; ! r && (netreq = *netreq_p)
; netreq_p++) {
if (! netreq->result)
if (! netreq->response_len)
continue;
nreplies++;
@ -604,7 +800,7 @@ create_getdns_response(getdns_dns_req *completed_request)
if (dnssec_return_status && netreq->bogus)
nbogus++;
else if (LDNS_RCODE_NOERROR ==
ldns_pkt_get_rcode(netreq->result))
GLDNS_RCODE_WIRE(netreq->response))
nanswers++;
if (! completed_request->dnssec_return_validation_chain) {