Merge pull request #181 from wtoorop/features/getdns_service

Features/getdns service
This commit is contained in:
Melinda Shore 2016-06-09 10:03:34 -08:00
commit 20ba3958fa
10 changed files with 894 additions and 716 deletions

View File

@ -601,8 +601,11 @@ _getdns_wire2msg_dict_scan(struct mem_funcs *mf,
getdns_return_t r = GETDNS_RETURN_GOOD;
getdns_dict *result = NULL, *header = NULL, *rr_dict = NULL;
_getdns_rr_iter rr_iter_storage, *rr_iter;
gldns_pkt_section section;
getdns_list *sections[4] = { NULL, NULL, NULL, NULL };
_getdns_section section;
getdns_list *sections[16] = { NULL, NULL, NULL, NULL
, NULL, NULL, NULL, NULL
, NULL, NULL, NULL, NULL
, NULL, NULL, NULL, NULL };
const uint8_t *eop; /* end of packet */
if (!wire || !*wire || !wire_len || !msg_dict)
@ -610,11 +613,11 @@ _getdns_wire2msg_dict_scan(struct mem_funcs *mf,
if (!(result = _getdns_dict_create_with_mf(mf)) ||
!(header = _getdns_dict_create_with_mf(mf)) ||
!(sections[GLDNS_SECTION_ANSWER]
!(sections[SECTION_ANSWER]
= _getdns_list_create_with_mf(mf)) ||
!(sections[GLDNS_SECTION_AUTHORITY]
!(sections[SECTION_AUTHORITY]
= _getdns_list_create_with_mf(mf)) ||
!(sections[GLDNS_SECTION_ADDITIONAL]
!(sections[SECTION_ADDITIONAL]
= _getdns_list_create_with_mf(mf))) {
r = GETDNS_RETURN_MEMORY_ERROR;
goto error;
@ -653,14 +656,14 @@ _getdns_wire2msg_dict_scan(struct mem_funcs *mf,
continue;
switch ((section = _getdns_rr_iter_section(rr_iter))) {
case GLDNS_SECTION_QUESTION:
case SECTION_QUESTION:
if ((r = _getdns_dict_set_this_dict(
result, "question", rr_dict)))
goto error;
break;
case GLDNS_SECTION_ANSWER:
case GLDNS_SECTION_AUTHORITY:
case GLDNS_SECTION_ADDITIONAL:
case SECTION_ANSWER:
case SECTION_AUTHORITY:
case SECTION_ADDITIONAL:
if ((r = _getdns_list_append_this_dict(
sections[section], rr_dict)))
goto error;
@ -672,27 +675,27 @@ _getdns_wire2msg_dict_scan(struct mem_funcs *mf,
rr_dict = NULL;
}
if (!(r = _getdns_dict_set_this_list(result, "answer",
sections[GLDNS_SECTION_ANSWER])))
sections[GLDNS_SECTION_ANSWER] = NULL;
sections[SECTION_ANSWER])))
sections[SECTION_ANSWER] = NULL;
else goto error;
if (!(r = _getdns_dict_set_this_list(result, "authority",
sections[GLDNS_SECTION_AUTHORITY])))
sections[GLDNS_SECTION_AUTHORITY] = NULL;
sections[SECTION_AUTHORITY])))
sections[SECTION_AUTHORITY] = NULL;
else goto error;
if (!(r = _getdns_dict_set_this_list(result, "additional",
sections[GLDNS_SECTION_ADDITIONAL])))
sections[GLDNS_SECTION_ADDITIONAL] = NULL;
sections[SECTION_ADDITIONAL])))
sections[SECTION_ADDITIONAL] = NULL;
else goto error;
*wire_len -= (eop - *wire);
*wire = eop;
error:
getdns_dict_destroy(rr_dict);
getdns_list_destroy(sections[GLDNS_SECTION_ADDITIONAL]);
getdns_list_destroy(sections[GLDNS_SECTION_AUTHORITY]);
getdns_list_destroy(sections[GLDNS_SECTION_ANSWER]);
getdns_list_destroy(sections[SECTION_ADDITIONAL]);
getdns_list_destroy(sections[SECTION_AUTHORITY]);
getdns_list_destroy(sections[SECTION_ANSWER]);
getdns_dict_destroy(header);
if (r)
getdns_dict_destroy(result);

File diff suppressed because it is too large Load Diff

View File

@ -84,76 +84,15 @@ static int
no_answer(getdns_dns_req *dns_req)
{
getdns_network_req **netreq_p, *netreq;
int new_canonical = 0, cnames_followed;
uint8_t canon_spc[256];
const uint8_t *canon;
size_t canon_len;
uint8_t owner_spc[256];
const uint8_t *owner;
size_t owner_len;
_getdns_rr_iter rr_spc, *rr;
_getdns_rdf_iter rdf_spc, *rdf;
for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
if (netreq->response_len == 0 ||
GLDNS_ANCOUNT(netreq->response) == 0)
continue;
canon = netreq->owner->name;
canon_len = netreq->owner->name_len;
if (netreq->request_type != GETDNS_RRTYPE_CNAME
&& GLDNS_ANCOUNT(netreq->response) > 1) do {
new_canonical = 0, cnames_followed = 0;
for ( rr = _getdns_rr_iter_init(&rr_spc
, netreq->response
, netreq->response_len)
; rr && _getdns_rr_iter_section(rr)
<= GLDNS_SECTION_ANSWER
; rr = _getdns_rr_iter_next(rr)) {
_getdns_rrset_spc answer;
if (_getdns_rr_iter_section(rr) !=
GLDNS_SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr->rr_type) !=
GETDNS_RRTYPE_CNAME)
continue;
owner = _getdns_owner_if_or_as_decompressed(
rr, owner_spc, &owner_len);
if (!_getdns_dname_equal(canon, owner))
continue;
if (!(rdf = _getdns_rdf_iter_init(
&rdf_spc, rr)))
continue;
canon = _getdns_rdf_if_or_as_decompressed(
rdf, canon_spc, &canon_len);
new_canonical = 1;
cnames_followed++;
}
} while (new_canonical && cnames_followed<MAX_CNAME_REFERRALS);
for ( rr = _getdns_rr_iter_init(&rr_spc
, netreq->response
, netreq->response_len)
; rr && _getdns_rr_iter_section(rr)
<= GLDNS_SECTION_ANSWER
; rr = _getdns_rr_iter_next(rr)) {
if (_getdns_rr_iter_section(rr) !=
GLDNS_SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr->rr_type) !=
netreq->request_type)
continue;
owner = _getdns_owner_if_or_as_decompressed(
rr, owner_spc, &owner_len);
if (_getdns_dname_equal(canon, owner))
return 0;
}
if (netreq->response_len > 0 &&
GLDNS_ANCOUNT(netreq->response) > 0 &&
_getdns_rrset_answer(&answer, netreq->response
, netreq->response_len))
return 0;
}
return 1;
}

View File

@ -478,7 +478,7 @@ _getdns_network_validate_tsig(getdns_network_req *req)
; rr
; rr = _getdns_rr_iter_next(rr)) {
if (_getdns_rr_iter_section(rr) == GLDNS_SECTION_ADDITIONAL &&
if (_getdns_rr_iter_section(rr) == SECTION_ADDITIONAL &&
gldns_read_uint16(rr->rr_type) == GETDNS_RRTYPE_TSIG)
break;
}
@ -501,7 +501,7 @@ _getdns_network_validate_tsig(getdns_network_req *req)
; rr
; rr = _getdns_rr_iter_next(rr)) {
if (_getdns_rr_iter_section(rr) == GLDNS_SECTION_ADDITIONAL &&
if (_getdns_rr_iter_section(rr) == SECTION_ADDITIONAL &&
gldns_read_uint16(rr->rr_type) == GETDNS_RRTYPE_TSIG)
break;
}

View File

@ -31,8 +31,25 @@
#include "rr-iter.h"
#include "config.h"
#include <ctype.h>
#include "gldns/rrdef.h"
int
_getdns_dname_equal(const uint8_t *s1, const uint8_t *s2)
{
uint8_t i;
for (;;) {
if (*s1 != *s2)
return 0;
else if (!*s1)
return 1;
for (i = *s1++, s2++; i > 0; i--, s1++, s2++)
if (*s1 != *s2 && tolower((unsigned char)*s1)
!= tolower((unsigned char)*s2))
return 0;
}
}
static void
rr_iter_find_nxt(_getdns_rr_iter *i)
{
@ -118,15 +135,6 @@ _getdns_single_rr_iter_init(
return find_rrtype(i);
}
_getdns_rr_iter *
_getdns_rr_iter_rewind(_getdns_rr_iter *i)
{
assert(i);
return _getdns_rr_iter_init(i, i->pkt, i->pkt_end - i->pkt);
}
_getdns_rr_iter *
_getdns_rr_iter_next(_getdns_rr_iter *i)
{
@ -232,6 +240,235 @@ _getdns_owner_if_or_as_decompressed(_getdns_rr_iter *i,
ff_bytes, len, 0);
}
_getdns_rrset *
_getdns_initialized_rrset_answer(_getdns_rrset_spc *query_rrset)
{
_getdns_rrset *rrset = &query_rrset->rrset;
uint16_t qtype = rrset->rr_type;
size_t cname_loop_protection;
assert(query_rrset);
/* Follow CNAMEs */
rrset->rr_type = GETDNS_RRTYPE_CNAME;
for ( cname_loop_protection = MAX_CNAME_REFERRALS
; cname_loop_protection > 0
; cname_loop_protection-- ) {
_getdns_rrtype_iter rr_spc, *rr;
_getdns_rdf_iter rdf_spc, *rdf;
if (!(rr = _getdns_rrtype_iter_init(&rr_spc, rrset)))
break;
if (!(rdf = _getdns_rdf_iter_init(&rdf_spc, &rr->rr_i)))
break;
query_rrset->name_len = sizeof(query_rrset->name_spc);
rrset->name = _getdns_rdf_if_or_as_decompressed(
rdf, query_rrset->name_spc, &query_rrset->name_len);
}
rrset->rr_type = qtype;
if (qtype == GETDNS_RRTYPE_CNAME &&
cname_loop_protection < MAX_CNAME_REFERRALS)
return rrset; /* The CNAME was the answer */
return _getdns_rrset_has_rrs(rrset) ? rrset : NULL;
}
_getdns_rrset *
_getdns_rrset_answer(_getdns_rrset_spc *spc, const uint8_t *pkt, size_t len)
{
_getdns_rr_iter rr_spc, *rr;
assert(spc);
spc->rrset.name = NULL;
spc->name_len = sizeof(spc->name_spc);
if ( !(rr = _getdns_rr_iter_init(&rr_spc, pkt, len))
|| _getdns_rr_iter_section(rr) != SECTION_QUESTION
|| !(spc->rrset.name = _getdns_owner_if_or_as_decompressed(
rr, spc->name_spc, &spc->name_len))
|| rr->nxt < rr->rr_type + 4)
return NULL;
spc->rrset.rr_class = rr_iter_class(rr);
spc->rrset.rr_type = rr_iter_type(rr);
spc->rrset.pkt = pkt;
spc->rrset.pkt_len = len;
spc->rrset.sections = SECTION_ANSWER;
return _getdns_initialized_rrset_answer(spc);
}
/* Utility function to compare owner name of rr with name */
static int rr_owner_equal(_getdns_rr_iter *rr, const uint8_t *name)
{
uint8_t owner_spc[256];
const uint8_t *owner;
size_t owner_len = sizeof(owner_spc);
return (owner = _getdns_owner_if_or_as_decompressed(rr, owner_spc
,&owner_len))
&& _getdns_dname_equal(owner, name);
}
/* First a few filter functions that filter a RR iterator to point only
* to RRs with certain constraints (and moves on otherwise).
*/
/* Filter that only iterates over the sections */
static inline _getdns_rr_iter *rr_iter_section(
_getdns_rr_iter *rr, _getdns_section sections)
{
while (rr && rr->pos && !(sections & _getdns_rr_iter_section(rr)))
rr = _getdns_rr_iter_next(rr);
return rr && rr->pos ? rr : NULL;
}
/* Filter that only iterates over RRs with a certain name/class/type */
static _getdns_rr_iter *rr_iter_name_class_type(_getdns_rr_iter *rr,
const uint8_t *name, uint16_t rr_class, uint16_t rr_type,
_getdns_section sections)
{
while (rr_iter_section(rr, sections) && !(
rr_iter_type(rr) == rr_type &&
rr_iter_class(rr) == rr_class &&
rr_owner_equal(rr, name)))
rr = _getdns_rr_iter_next(rr);
return rr && rr->pos ? rr : NULL;
}
/* Filter that only iterates over RRs that do not have a name/class/type */
static _getdns_rr_iter *rr_iter_not_name_class_type(_getdns_rr_iter *rr,
const uint8_t *name, uint16_t rr_class, uint16_t rr_type,
_getdns_section sections)
{
while (rr_iter_section(rr, sections) && (
rr_iter_type(rr) == GETDNS_RRTYPE_RRSIG || (
rr_iter_type(rr) == rr_type &&
rr_iter_class(rr) == rr_class &&
rr_owner_equal(rr, name))))
rr = _getdns_rr_iter_next(rr);
return rr && rr->pos ? rr : NULL;
}
/* Filter that only iterates over RRs that are of type RRSIG, that cover
* a RRset with a certain name/class/type
*/
static _getdns_rr_iter *rr_iter_rrsig_covering(_getdns_rr_iter *rr,
const uint8_t *name, uint16_t rr_class, uint16_t rr_type,
_getdns_section sections)
{
while (rr_iter_section(rr, sections) && !(
rr_iter_type(rr) == GETDNS_RRTYPE_RRSIG &&
rr_iter_class(rr) == rr_class &&
rr->rr_type + 12 <= rr->nxt &&
gldns_read_uint16(rr->rr_type + 10) == rr_type &&
rr_owner_equal(rr, name)))
rr = _getdns_rr_iter_next(rr);
return rr && rr->pos ? rr : NULL;
}
_getdns_rrtype_iter *
_getdns_rrtype_iter_next(_getdns_rrtype_iter *i)
{
return (_getdns_rrtype_iter *) rr_iter_name_class_type(
_getdns_rr_iter_next(&i->rr_i),
i->rrset->name, i->rrset->rr_class, i->rrset->rr_type,
i->rrset->sections);
}
_getdns_rrtype_iter *
_getdns_rrtype_iter_init(_getdns_rrtype_iter *i, _getdns_rrset *rrset)
{
i->rrset = rrset;
return (_getdns_rrtype_iter *) rr_iter_name_class_type(
_getdns_rr_iter_init(&i->rr_i, rrset->pkt, rrset->pkt_len ),
i->rrset->name, i->rrset->rr_class, i->rrset->rr_type,
i->rrset->sections);
}
_getdns_rrsig_iter *
_getdns_rrsig_iter_next(_getdns_rrsig_iter *i)
{
return (_getdns_rrsig_iter *) rr_iter_rrsig_covering(
_getdns_rr_iter_next(&i->rr_i),
i->rrset->name, i->rrset->rr_class, i->rrset->rr_type,
i->rrset->sections);
}
_getdns_rrsig_iter *
_getdns_rrsig_iter_init(_getdns_rrsig_iter *i, _getdns_rrset *rrset)
{
i->rrset = rrset;
return (_getdns_rrsig_iter *) rr_iter_rrsig_covering(
_getdns_rr_iter_init(&i->rr_i, rrset->pkt, rrset->pkt_len),
i->rrset->name, i->rrset->rr_class, i->rrset->rr_type,
i->rrset->sections);
}
_getdns_rrset_iter *
_getdns_rrset_iter_init(_getdns_rrset_iter *i,
const uint8_t *pkt, size_t pkt_len, _getdns_section sections)
{
_getdns_rr_iter *rr;
i->rrset.name = i->name_spc;
i->rrset.pkt = pkt;
i->rrset.pkt_len = pkt_len;
i->rrset.sections = sections;
i->name_len = 0;
for ( rr = _getdns_rr_iter_init(&i->rr_i, pkt, pkt_len)
;(rr = rr_iter_section(rr, sections))
; rr = _getdns_rr_iter_next(rr)) {
if ((i->rrset.rr_type = rr_iter_type(rr))
== GETDNS_RRTYPE_RRSIG)
continue;
i->rrset.rr_class = rr_iter_class(rr);
if (!(i->rrset.name = _getdns_owner_if_or_as_decompressed(
rr, i->name_spc, &i->name_len)))
continue;
return i;
}
return NULL;
}
_getdns_rrset_iter *_getdns_rrset_iter_next(_getdns_rrset_iter *i)
{
_getdns_rr_iter *rr;
if (!(rr = i && i->rr_i.pos ? &i->rr_i : NULL))
return NULL;
if (!(rr = rr_iter_not_name_class_type(rr,
i->rrset.name, i->rrset.rr_class, i->rrset.rr_type,
i->rrset.sections)))
return NULL;
i->rrset.rr_type = rr_iter_type(rr);
i->rrset.rr_class = rr_iter_class(rr);
if (!(i->rrset.name = _getdns_owner_if_or_as_decompressed(
rr, i->name_spc, &i->name_len)))
/* This is safe, because rr_iter_not_name_class_type will shift
* the iterator forward because at least name does not match.
* Goal is to skip broken compression pointer issues but keep
* processing the packet.
*/
return _getdns_rrset_iter_next(i);
return i;
}
static _getdns_rdf_iter *
rdf_iter_find_nxt(_getdns_rdf_iter *i)
{
@ -299,7 +536,7 @@ _getdns_rdf_iter_init(_getdns_rdf_iter *i, _getdns_rr_iter *rr)
i->end = NULL;
/* rr_iter already done or in question section */
if (!rr->pos || _getdns_rr_iter_section(rr) == GLDNS_SECTION_QUESTION)
if (!rr->pos || _getdns_rr_iter_section(rr) == SECTION_QUESTION)
goto done;
i->pkt = rr->pkt;

View File

@ -32,10 +32,20 @@
#ifndef RR_ITER_H_
#define RR_ITER_H_
#include "getdns/getdns.h"
#include "rr-dict.h"
#include "gldns/pkthdr.h"
#include "gldns/gbuffer.h"
typedef enum _getdns_section {
SECTION_QUESTION = 1,
SECTION_ANSWER = 2,
SECTION_AUTHORITY = 4,
SECTION_ADDITIONAL = 8,
SECTION_ANY = 15,
SECTION_NO_QUESTION = 14,
SECTION_NO_ADDITIONAL = 6
} _getdns_section;
int _getdns_dname_equal(const uint8_t *s1, const uint8_t *s2);
typedef struct _getdns_rr_iter {
const uint8_t *pkt;
@ -65,32 +75,115 @@ _getdns_rr_iter *_getdns_rr_iter_init(_getdns_rr_iter *i,
_getdns_rr_iter *_getdns_single_rr_iter_init(_getdns_rr_iter *i,
const uint8_t *wire, const size_t wire_len);
_getdns_rr_iter *_getdns_rr_iter_rewind(_getdns_rr_iter *i);
static inline _getdns_rr_iter *_getdns_rr_iter_rewind(_getdns_rr_iter *i)
{ return _getdns_rr_iter_init(i, i->pkt, i->pkt_end - i->pkt); }
_getdns_rr_iter *_getdns_rr_iter_next(_getdns_rr_iter *i);
const uint8_t *_getdns_owner_if_or_as_decompressed(
_getdns_rr_iter *i, uint8_t *ff_bytes, size_t *len);
static inline gldns_pkt_section
static inline _getdns_section
_getdns_rr_iter_section(_getdns_rr_iter *i)
{
return !i->pkt ? (i->nxt - i->rr_type == 4 ? GLDNS_SECTION_QUESTION
: GLDNS_SECTION_ANSWER )
: i->n < GLDNS_QDCOUNT(i->pkt) ? GLDNS_SECTION_QUESTION
return !i->pkt ? (i->nxt - i->rr_type == 4 ? SECTION_QUESTION
: SECTION_ANSWER )
: i->n < GLDNS_QDCOUNT(i->pkt) ? SECTION_QUESTION
: i->n < GLDNS_QDCOUNT(i->pkt)
+ GLDNS_ANCOUNT(i->pkt) ? GLDNS_SECTION_ANSWER
+ GLDNS_ANCOUNT(i->pkt) ? SECTION_ANSWER
: i->n < GLDNS_QDCOUNT(i->pkt)
+ GLDNS_ANCOUNT(i->pkt)
+ GLDNS_NSCOUNT(i->pkt) ? GLDNS_SECTION_AUTHORITY
+ GLDNS_NSCOUNT(i->pkt) ? SECTION_AUTHORITY
: i->n < GLDNS_QDCOUNT(i->pkt)
+ GLDNS_ANCOUNT(i->pkt)
+ GLDNS_NSCOUNT(i->pkt)
+ GLDNS_ARCOUNT(i->pkt) ? GLDNS_SECTION_ADDITIONAL
: GLDNS_SECTION_ANY;
+ GLDNS_ARCOUNT(i->pkt) ? SECTION_ADDITIONAL
: SECTION_ANY;
}
typedef struct piv_getdns_rdf_iter {
/* Utility functions to read rr_type and rr_class from a rr iterator */
static inline uint16_t rr_iter_type(_getdns_rr_iter *rr)
{ return rr->rr_type + 2 <= rr->nxt ? gldns_read_uint16(rr->rr_type) : 0; }
static inline uint16_t rr_iter_class(_getdns_rr_iter *rr)
{ return rr->rr_type + 4 <= rr->nxt ? gldns_read_uint16(rr->rr_type + 2) : 0; }
typedef struct _getdns_rrset {
const uint8_t *name;
uint16_t rr_class;
uint16_t rr_type;
const uint8_t *pkt;
size_t pkt_len;
_getdns_section sections;
} _getdns_rrset;
typedef struct _getdns_rrset_spc {
_getdns_rrset rrset;
uint8_t name_spc[256];
size_t name_len;
} _getdns_rrset_spc;
_getdns_rrset *_getdns_rrset_answer(
_getdns_rrset_spc *rrset2init, const uint8_t *pkt, size_t pkt_len);
_getdns_rrset *_getdns_initialized_rrset_answer(
_getdns_rrset_spc *query_rrset);
typedef struct _getdns_rrtype_iter {
_getdns_rr_iter rr_i;
_getdns_rrset *rrset;
} _getdns_rrtype_iter;
_getdns_rrtype_iter *_getdns_rrtype_iter_init(
_getdns_rrtype_iter *i, _getdns_rrset *rrset);
_getdns_rrtype_iter *_getdns_rrtype_iter_next(_getdns_rrtype_iter *i);
static inline int _getdns_rrset_has_rrs(_getdns_rrset *rrset)
{
_getdns_rrtype_iter rr_spc;
return _getdns_rrtype_iter_init(&rr_spc, rrset) != NULL;
}
typedef struct _getdns_rrsig_iter {
_getdns_rr_iter rr_i;
_getdns_rrset *rrset;
} _getdns_rrsig_iter;
_getdns_rrsig_iter *_getdns_rrsig_iter_init(
_getdns_rrsig_iter *i, _getdns_rrset *rrset);
_getdns_rrsig_iter *_getdns_rrsig_iter_next(_getdns_rrsig_iter *i);
static inline int _getdns_rrset_has_rrsigs(_getdns_rrset *rrset)
{
_getdns_rrsig_iter rrsig;
return _getdns_rrsig_iter_init(&rrsig, rrset) != NULL;
}
/* The _getdns_rrset_iter manifests an iterator of a wireformat packet that
* will return all unique rrsets within that packet in turn.
*/
typedef struct _getdns_rrset_iter {
_getdns_rrset rrset;
uint8_t name_spc[256];
size_t name_len;
_getdns_rr_iter rr_i;
} _getdns_rrset_iter;
_getdns_rrset_iter *_getdns_rrset_iter_init(_getdns_rrset_iter *i,
const uint8_t *pkt, size_t pkt_len, _getdns_section sections);
_getdns_rrset_iter *_getdns_rrset_iter_next(_getdns_rrset_iter *i);
static inline _getdns_rrset *_getdns_rrset_iter_value(_getdns_rrset_iter *i)
{ return i && i->rr_i.pos ? &i->rrset : NULL; }
static inline _getdns_rrset_iter *_getdns_rrset_iter_rewind(_getdns_rrset_iter *i)
{ return _getdns_rrset_iter_init(i, i->rrset.pkt, i->rrset.pkt_len, i->rrset.sections); }
typedef struct _getdns_rdf_iter {
const uint8_t *pkt;
const uint8_t *pkt_end;
const _getdns_rdata_def *rdd_pos;
@ -112,4 +205,5 @@ _getdns_rdf_iter *_getdns_rdf_iter_init_at(_getdns_rdf_iter *i,
const uint8_t *_getdns_rdf_if_or_as_decompressed(
_getdns_rdf_iter *i, uint8_t *ff_bytes, size_t *len);
#endif

View File

@ -225,8 +225,7 @@ match_edns_opt_rr(uint16_t code, uint8_t *response, size_t response_len,
; rr_iter
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
if (_getdns_rr_iter_section(rr_iter) !=
GLDNS_SECTION_ADDITIONAL)
if (_getdns_rr_iter_section(rr_iter) != SECTION_ADDITIONAL)
continue;
if (gldns_read_uint16(rr_iter->rr_type) != GETDNS_RRTYPE_OPT)

View File

@ -8,7 +8,6 @@
"answer": [],
"answer_type": GETDNS_NAMETYPE_DNS,
"authority": [],
"canonical_name": <bindata for bogus.nlnetlabs.nl.>,
"header":
{
"aa": 0,

View File

@ -37,7 +37,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include "config.h"
#include "getdns/getdns.h"
#include "dict.h"
@ -178,7 +177,7 @@ _getdns_rr_iter2rr_dict_canonical(
owner_len = bin_size;
}
/* question */
if (_getdns_rr_iter_section(i) == GLDNS_SECTION_QUESTION) {
if (_getdns_rr_iter_section(i) == SECTION_QUESTION) {
if (getdns_dict_set_int(rr_dict, "qtype",
(uint32_t) gldns_read_uint16(i->rr_type)) ||
@ -438,21 +437,6 @@ _getdns_rr_iter2rr_dict(struct mem_funcs *mf, _getdns_rr_iter *i)
return _getdns_rr_iter2rr_dict_canonical(mf, i, NULL);
}
int
_getdns_dname_equal(const uint8_t *s1, const uint8_t *s2)
{
uint8_t i;
for (;;) {
if (*s1 != *s2)
return 0;
else if (!*s1)
return 1;
for (i = *s1++, s2++; i > 0; i--, s1++, s2++)
if (*s1 != *s2 && tolower((unsigned char)*s1)
!= tolower((unsigned char)*s2))
return 0;
}
}
inline static getdns_dict *
set_dict(getdns_dict **var, getdns_dict *value)
@ -478,6 +462,30 @@ inline static int has_all_numeric_label(const uint8_t *dname)
return 0;
}
typedef struct _srv_rr {
_getdns_rr_iter i;
unsigned running_sum;
} _srv_rr;
typedef struct _srvs {
size_t capacity;
size_t count;
_srv_rr *rrs;
} _srvs;
static int _grow_srvs(struct mem_funcs *mf, _srvs *srvs)
{
_srv_rr *new_rrs;
if (!(new_rrs = GETDNS_XREALLOC(
*mf, srvs->rrs, _srv_rr, srvs->capacity * 2)))
return 0; /* Memory error */
srvs->capacity *= 2;
srvs->rrs = new_rrs;
return 1; /* Success */
}
#define SET_WIRE_INT(X,Y) if (getdns_dict_set_int(header, #X , (int) \
GLDNS_ ## Y ## _WIRE(req->response))) goto error
#define SET_WIRE_BIT(X,Y) if (getdns_dict_set_int(header, #X , \
@ -485,9 +493,9 @@ inline static int has_all_numeric_label(const uint8_t *dname)
#define SET_WIRE_CNT(X,Y) if (getdns_dict_set_int(header, #X , (int) \
GLDNS_ ## Y (req->response))) goto error
getdns_dict *
static getdns_dict *
_getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
getdns_list *just_addrs, int *rrsigs_in_answer)
getdns_list *just_addrs, int *rrsigs_in_answer, _srvs *srvs)
{
/* turn a packet into this glorious structure
*
@ -531,28 +539,30 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
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_list *sections[16] = { NULL, NULL
, getdns_list_create_with_context(context)
, NULL
, getdns_list_create_with_context(context)
, NULL, NULL, NULL
, getdns_list_create_with_context(context)
, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
getdns_dict *rr_dict = NULL;
_getdns_rr_iter rr_iter_storage, *rr_iter;
_getdns_rdf_iter rdf_iter_storage, *rdf_iter;
size_t bin_size;
const uint8_t *bin_data;
gldns_pkt_section section;
uint8_t canonical_name_space[256], owner_name_space[256],
query_name_space[256];
const uint8_t *canonical_name, *owner_name, *query_name;
size_t canonical_name_len = sizeof(canonical_name_space),
owner_name_len = sizeof(owner_name_space),
_getdns_section section;
uint8_t owner_name_space[256], query_name_space[256];
const uint8_t *owner_name, *query_name;
size_t owner_name_len = sizeof(owner_name_space),
query_name_len = sizeof(query_name_space);
int new_canonical = 0, cnames_followed,
request_answered, all_numeric_label;
int all_numeric_label;
uint16_t rr_type;
getdns_dict *header = NULL;
getdns_list *bad_dns = NULL;
_getdns_rrset_spc answer_spc;
_getdns_rrset *answer;
if (!result)
goto error;
@ -582,9 +592,6 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
goto error;
header = NULL;
canonical_name = req->owner->name;
canonical_name_len = req->owner->name_len;
if (req->query &&
(rr_iter = _getdns_rr_iter_init(&rr_iter_storage, req->query
, req->response - req->query)))
@ -605,7 +612,7 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
continue;
section = _getdns_rr_iter_section(rr_iter);
if (section == GLDNS_SECTION_QUESTION) {
if (section == SECTION_QUESTION) {
if (!query_name)
query_name
= _getdns_owner_if_or_as_decompressed(
@ -617,11 +624,11 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
continue;
}
rr_type = gldns_read_uint16(rr_iter->rr_type);
if (section > GLDNS_SECTION_QUESTION &&
if (section > SECTION_QUESTION &&
rr_type == GETDNS_RRTYPE_RRSIG && rrsigs_in_answer)
*rrsigs_in_answer = 1;
if (section != GLDNS_SECTION_ANSWER) {
if (section != SECTION_ANSWER) {
if (_getdns_list_append_this_dict(
sections[section], rr_dict))
goto error;
@ -637,38 +644,28 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
continue;
}
if (_getdns_list_append_this_dict(
sections[GLDNS_SECTION_ANSWER], rr_dict))
sections[SECTION_ANSWER], rr_dict))
goto error;
else rr_dict = NULL;
if (rr_type == GETDNS_RRTYPE_CNAME) {
if (srvs->capacity && rr_type == GETDNS_RRTYPE_SRV) {
if (srvs->count >= srvs->capacity &&
!_grow_srvs(&context->mf, srvs))
goto error;
owner_name_len = sizeof(owner_name_space);
owner_name = _getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!_getdns_dname_equal(canonical_name, owner_name))
continue;
if (!(rdf_iter = _getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
new_canonical = 1;
canonical_name = _getdns_rdf_if_or_as_decompressed(
rdf_iter,canonical_name_space,&canonical_name_len);
srvs->rrs[srvs->count++].i = *rr_iter;
continue;
}
if (rr_type != GETDNS_RRTYPE_A && rr_type != GETDNS_RRTYPE_AAAA)
continue;
if (!just_addrs)
continue;
if (!(rdf_iter = _getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
if (!just_addrs)
continue;
bin_size = rdf_iter->nxt - rdf_iter->pos;
bin_data = rdf_iter->pos;
if (!set_dict(&rr_dict, getdns_dict_create_with_context(context)) ||
@ -686,18 +683,18 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
rr_dict = NULL;
}
if (!_getdns_dict_set_this_list(result, "answer",
sections[GLDNS_SECTION_ANSWER]))
sections[GLDNS_SECTION_ANSWER] = NULL;
sections[SECTION_ANSWER]))
sections[SECTION_ANSWER] = NULL;
else goto error;
if (!_getdns_dict_set_this_list(result, "authority",
sections[GLDNS_SECTION_AUTHORITY]))
sections[GLDNS_SECTION_AUTHORITY] = NULL;
sections[SECTION_AUTHORITY]))
sections[SECTION_AUTHORITY] = NULL;
else goto error;
if (!_getdns_dict_set_this_list(result, "additional",
sections[GLDNS_SECTION_ADDITIONAL]))
sections[GLDNS_SECTION_ADDITIONAL] = NULL;
sections[SECTION_ADDITIONAL]))
sections[SECTION_ADDITIONAL] = NULL;
else goto error;
/* other stuff
@ -706,42 +703,13 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
if (getdns_dict_set_int(result, "answer_type", GETDNS_NAMETYPE_DNS))
goto error;
cnames_followed = new_canonical;
while (cnames_followed < MAX_CNAME_REFERRALS && new_canonical) {
new_canonical = 0;
answer = _getdns_rrset_answer(&answer_spc, req->response
, req->response_len);
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
, req->response
, req->response_len)
; rr_iter && _getdns_rr_iter_section(rr_iter)
<= GLDNS_SECTION_ANSWER
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
if (_getdns_rr_iter_section(rr_iter) !=
GLDNS_SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr_iter->rr_type) !=
GETDNS_RRTYPE_CNAME)
continue;
owner_name = _getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!_getdns_dname_equal(canonical_name, owner_name))
continue;
if (!(rdf_iter = _getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
canonical_name = _getdns_rdf_if_or_as_decompressed(
rdf_iter,canonical_name_space,&canonical_name_len);
new_canonical = 1;
cnames_followed++;
}
}
if (_getdns_dict_set_const_bindata(
result, "canonical_name", canonical_name_len, canonical_name))
if (answer_spc.rrset.name &&
_getdns_dict_set_const_bindata(result, "canonical_name"
, answer_spc.name_len
, answer_spc.rrset.name))
goto error;
if (!req->owner->add_warning_for_bad_dns)
@ -750,35 +718,15 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
if (!(bad_dns = getdns_list_create_with_context(context)))
goto error;
if (cnames_followed && req->request_type != GETDNS_RRTYPE_CNAME) {
request_answered = 0;
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
, req->response
, req->response_len)
; rr_iter && _getdns_rr_iter_section(rr_iter)
<= GLDNS_SECTION_ANSWER
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
if ( !answer
&& req->request_type != GETDNS_RRTYPE_CNAME
&& query_name
&& answer_spc.rrset.name
&& !_getdns_dname_equal(query_name, answer_spc.rrset.name)
&& _getdns_list_append_int(bad_dns
, GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE))
goto error;
if (_getdns_rr_iter_section(rr_iter) !=
GLDNS_SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr_iter->rr_type) !=
req->request_type)
continue;
owner_name=_getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space,&owner_name_len);
if (_getdns_dname_equal(
canonical_name, owner_name)) {
request_answered = 1;
break;
}
}
if (!request_answered &&
_getdns_list_append_int(bad_dns,
GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE))
goto error;
}
all_numeric_label = 0;
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
, req->response
@ -794,7 +742,7 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
break;
}
if (_getdns_rr_iter_section(rr_iter) ==
GLDNS_SECTION_QUESTION)
SECTION_QUESTION)
continue;
for ( rdf_iter = _getdns_rdf_iter_init(&rdf_iter_storage, rr_iter)
@ -827,15 +775,15 @@ error:
success:
getdns_dict_destroy(header);
getdns_dict_destroy(rr_dict);
getdns_list_destroy(sections[GLDNS_SECTION_ADDITIONAL]);
getdns_list_destroy(sections[GLDNS_SECTION_AUTHORITY]);
getdns_list_destroy(sections[GLDNS_SECTION_ANSWER]);
getdns_list_destroy(sections[SECTION_ADDITIONAL]);
getdns_list_destroy(sections[SECTION_AUTHORITY]);
getdns_list_destroy(sections[SECTION_ANSWER]);
getdns_dict_destroy(question);
getdns_list_destroy(bad_dns);
return result;
}
getdns_dict *
static getdns_dict *
_getdns_create_call_reporting_dict(
getdns_context *context, getdns_network_req *netreq)
{
@ -919,11 +867,180 @@ _getdns_create_call_reporting_dict(
return netreq_debug;
}
static inline int _srv_prio(_getdns_rr_iter *x)
{ return x->nxt < x->rr_type+12
? 65536 : (int)gldns_read_uint16(x->rr_type+10); }
static inline int _srv_weight(_getdns_rr_iter *x)
{ return x->nxt < x->rr_type+14 ? 0 : (int)gldns_read_uint16(x->rr_type+12); }
static int _srv_cmp(const void *a, const void *b)
{
return _srv_prio((_getdns_rr_iter *)a)
- _srv_prio((_getdns_rr_iter *)b);
}
static void _rfc2782_sort(_srv_rr *start, _srv_rr *end)
{
int running_sum, n;
_srv_rr *i, *j, swap;
/* First move all SRVs with weight 0 to the beginning of the list */
for (i = start; i < end && _srv_weight(&i->i) == 0; i++)
; /* pass */
for (j = i + 1; j < end; j++) {
if (_srv_weight(&j->i) == 0) {
swap = *i;
*i = *j;
*j = swap;
i++;
}
}
/* Now all SRVs are at the beginning, calculate running_sum */
running_sum = 0;
for (i = start; i < end; i++) {
running_sum += _srv_weight(&i->i);
i->running_sum = running_sum;
}
n = arc4random_uniform(running_sum);
for (i = start; i < end; i++) {
if (i->running_sum >= n)
break;
}
if (i > start && i < end) {
swap = *start;
*start = *i;
*i = swap;
_rfc2782_sort(start + 1, end);
}
}
static getdns_list *
_create_srv_addrs(getdns_context *context, _srvs *srvs)
{
getdns_list *srv_addrs;
size_t i, j;
qsort(srvs->rrs, srvs->count, sizeof(_srv_rr), _srv_cmp);
/* The SRVs are now sorted by priority (lowest first). Now determine
* server selection order for the SRVs with the same priority with
* the algorithm described in RFC2782:
*
* To select a target to be contacted next, arrange all SRV RRs
* (that have not been ordered yet) in any order, except that all
* those with weight 0 are placed at the beginning of the list.
*
* Compute the sum of the weights of those RRs, and with each RR
* associate the running sum in the selected order. Then choose a
* uniform random number between 0 and the sum computed
* (inclusive), and select the RR whose running sum value is the
* first in the selected order which is greater than or equal to
* the random number selected. The target host specified in the
* selected SRV RR is the next one to be contacted by the client.
* Remove this SRV RR from the set of the unordered SRV RRs and
* apply the described algorithm to the unordered SRV RRs to select
* the next target host. Continue the ordering process until there
* are no unordered SRV RRs. This process is repeated for each
* Priority.
*/
for (i = 0; i < srvs->count; i = j) {
/* Determine range of SRVs with same priority */
for ( j = i + 1
; j < srvs->count && _srv_prio(&srvs->rrs[i].i)
== _srv_prio(&srvs->rrs[j].i)
; j++)
; /* pass */
if (j == i + 1)
continue;
/* SRVs with same prio range from i till j (exclusive). */
_rfc2782_sort(srvs->rrs + i, srvs->rrs + j);
}
if (!(srv_addrs = getdns_list_create_with_context(context)))
return NULL;
for (i = 0; i < srvs->count; i++) {
_getdns_rr_iter *rr = &srvs->rrs[i].i;
getdns_dict *d;
_getdns_rdf_iter rdf_storage, *rdf;
const uint8_t *dname;
uint8_t dname_spc[256];
size_t dname_sz = sizeof(dname_spc);
_getdns_rrset a;
_getdns_rrtype_iter a_rr_spc, *a_rr;
int addresses_found = 0;
if ( !(d = getdns_dict_create_with_context(context))
|| !(rdf = _getdns_rdf_iter_init_at(&rdf_storage, rr, 2))
|| !(rdf->rdd_pos->type & GETDNS_RDF_INTEGER)
|| (rdf->rdd_pos->type & GETDNS_RDF_FIXEDSZ) != 2
|| getdns_dict_set_int(d, "port", (uint32_t)
gldns_read_uint16(rdf->pos))
|| !(rdf = _getdns_rdf_iter_init_at(&rdf_storage, rr, 3))
|| !(rdf->rdd_pos->type & GETDNS_RDF_DNAME)
|| !(dname = _getdns_rdf_if_or_as_decompressed(
rdf, dname_spc, &dname_sz))
|| _getdns_dict_set_const_bindata(
d, "domain_name", dname_sz, dname)) {
/* error */
getdns_dict_destroy(d);
continue;
}
a.name = dname;
a.rr_class = rr_iter_class(rr);
a.rr_type = GETDNS_RRTYPE_AAAA;
a.pkt = rr->pkt;
a.pkt_len = rr->pkt_end - rr->pkt;
a.sections = SECTION_ADDITIONAL;
for ( a_rr = _getdns_rrtype_iter_init(&a_rr_spc, &a)
; a_rr ; a_rr = _getdns_rrtype_iter_next(a_rr)) {
if ( a_rr->rr_i.nxt - (a_rr->rr_i.rr_type + 10) == 16
&& !getdns_dict_util_set_string(
d, "address_type", "IPv6")
&& !_getdns_dict_set_const_bindata(
d, "address_data", 16,
a_rr->rr_i.rr_type + 10)
&& !_getdns_list_append_dict(srv_addrs, d))
addresses_found++;
}
a.rr_type = GETDNS_RRTYPE_A;
for ( a_rr = _getdns_rrtype_iter_init(&a_rr_spc, &a)
; a_rr ; a_rr = _getdns_rrtype_iter_next(a_rr)) {
if ( a_rr->rr_i.nxt - (a_rr->rr_i.rr_type + 10) ==4
&& !getdns_dict_util_set_string(
d, "address_type", "IPv4")
&& !_getdns_dict_set_const_bindata(
d, "address_data", 4,
a_rr->rr_i.rr_type + 10)
&& !_getdns_list_append_dict(srv_addrs, d))
addresses_found++;
}
if ( addresses_found
|| _getdns_list_append_this_dict(srv_addrs, d))
getdns_dict_destroy(d);
}
return srv_addrs;
}
getdns_dict *
_getdns_create_getdns_response(getdns_dns_req *completed_request)
{
getdns_dict *result;
getdns_list *just_addrs = NULL;
getdns_list *srv_addrs = NULL;
getdns_list *replies_full;
getdns_list *replies_tree;
getdns_list *call_reporting = NULL;
@ -933,6 +1050,7 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
getdns_bindata *canonical_name = NULL;
int nreplies = 0, nanswers = 0, nsecure = 0, ninsecure = 0, nbogus = 0;
getdns_dict *netreq_debug;
_srvs srvs = { 0, 0, NULL };
/* info (bools) about dns_req */
int dnssec_return_status;
@ -957,6 +1075,16 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
just_addrs = getdns_list_create_with_context(
completed_request->context);
else if (
completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_SRV) {
srvs.capacity = 100;
if (!(srvs.rrs = GETDNS_XMALLOC(
context->mf, _srv_rr, srvs.capacity))) {
srvs.capacity = 0;
goto error_free_result;
}
}
if (getdns_dict_set_int(result, GETDNS_STR_KEY_ANSWER_TYPE,
GETDNS_NAMETYPE_DNS))
goto error_free_result;
@ -1003,14 +1131,13 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
continue;
}
if (!(reply = _getdns_create_reply_dict(context,
netreq, just_addrs, &rrsigs_in_answer)))
netreq, just_addrs, &rrsigs_in_answer, &srvs)))
goto error;
if (!canonical_name) {
if (getdns_dict_get_bindata(
reply, "canonical_name", &canonical_name))
goto error;
if (getdns_dict_set_bindata(
if (!getdns_dict_get_bindata(
reply, "canonical_name", &canonical_name) &&
getdns_dict_set_bindata(
result, "canonical_name", canonical_name))
goto error;
}
@ -1059,6 +1186,11 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
goto error;
replies_tree = NULL;
if (!canonical_name &&
_getdns_dict_set_const_bindata(result, "canonical_name",
completed_request->name_len, completed_request->name))
goto error;
if (call_reporting) {
if (_getdns_dict_set_this_list(
result, "call_reporting", call_reporting))
@ -1075,6 +1207,14 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
goto error_free_result;
just_addrs = NULL;
}
if (srvs.capacity) {
if (!(srv_addrs = _create_srv_addrs(context, &srvs)) ||
_getdns_dict_set_this_list(
result, "srv_addresses", srv_addrs))
goto error_free_result;
GETDNS_FREE(context->mf, srvs.rrs);
}
if (getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS,
nreplies == 0 ? GETDNS_RESPSTATUS_ALL_TIMEOUT :
completed_request->dnssec_return_only_secure && nsecure == 0 && ninsecure > 0
@ -1094,6 +1234,9 @@ error_free_call_reporting:
error_free_replies_full:
getdns_list_destroy(replies_full);
error_free_result:
if (srvs.capacity)
GETDNS_FREE(context->mf, srvs.rrs);
getdns_list_destroy(srv_addrs);
getdns_list_destroy(just_addrs);
getdns_dict_destroy(result);
return NULL;

View File

@ -149,13 +149,8 @@ _getdns_rr_iter2rr_dict_canonical(
struct getdns_dns_req;
struct getdns_dict *_getdns_create_getdns_response(struct getdns_dns_req *completed_request);
getdns_dict *_getdns_create_reply_dict(getdns_context *context,
getdns_network_req *req, getdns_list *just_addrs, int *rrsigs_in_answer);
getdns_return_t _getdns_validate_dname(const char* dname);
int _getdns_dname_equal(const uint8_t *s1, const uint8_t *s2);
uint8_t *_getdns_list2wire(
getdns_list *l, uint8_t *buf, size_t *buf_len, struct mem_funcs *mf);