Query for DS i.s.o. SOA to find zonecuts

Because of broken setups that have zonecuts without SOA:

```
$ drill -T www.gslb.kpn.com A
.	518400	IN	NS	i.root-servers.net.
com.	172800	IN	NS	a.gtld-servers.net.
kpn.com.	172800	IN	NS	ns1.kpn.net.
kpn.com.	172800	IN	NS	ns2.kpn.net.
gslb.kpn.com.	3600	IN	NS	gss1.kpn.com.
gslb.kpn.com.	3600	IN	NS	gss2.kpn.com.
www.gslb.kpn.com.	10	IN	A	145.7.170.135
```

but

```
$ drill gslb.kpn.com SOA
;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 48303
;; flags: qr rd ra ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; gslb.kpn.com.	IN	SOA

;; ANSWER SECTION:

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 8 msec
;; SERVER: 185.49.140.100
;; WHEN: Fri Mar  2 14:13:21 2018
;; MSG SIZE  rcvd: 30
```
This commit is contained in:
Willem Toorop 2018-03-02 14:14:28 +01:00
parent abc69f96fe
commit e29cfb6b6a
1 changed files with 14 additions and 123 deletions

View File

@ -506,8 +506,6 @@ struct chain_node {
getdns_network_req *ds_req;
int ds_signer;
getdns_network_req *soa_req;
chain_head *chains;
};
@ -521,7 +519,6 @@ struct chain_node {
static void val_chain_sched(chain_head *head, const uint8_t *dname);
static void val_chain_sched_ds(chain_head *head, const uint8_t *dname);
static void val_chain_sched_signer(chain_head *head, _getdns_rrsig_iter *rrsig);
static void val_chain_sched_soa(chain_head *head, const uint8_t *dname);
static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
chain_head **chain_p, _getdns_rrset *rrset, getdns_network_req *netreq)
@ -663,7 +660,6 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
node->dnskey.sections = head->rrset.sections;
node->ds_req = NULL;
node->dnskey_req = NULL;
node->soa_req = NULL;
node->ds_signer = -1;
node->dnskey_signer = -1;
@ -822,9 +818,9 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
if (rrset->rr_type == GETDNS_RRTYPE_SOA)
val_chain_sched_ds(head, rrset->name);
else if (rrset->rr_type == GETDNS_RRTYPE_CNAME)
val_chain_sched_soa(head, rrset->name + *rrset->name + 1);
val_chain_sched_ds(head, rrset->name + *rrset->name + 1);
else
val_chain_sched_soa(head, rrset->name);
val_chain_sched_ds(head, rrset->name);
}
}
@ -841,6 +837,7 @@ static void add_question2val_chain(struct mem_funcs *mf,
_getdns_rrset_iter *i, i_spc;
_getdns_rrset *rrset;
_getdns_rrsig_iter rrsig_spc;
size_t n_soas;
_getdns_rrset_spc q_rrset;
chain_head *head;
@ -867,26 +864,29 @@ static void add_question2val_chain(struct mem_funcs *mf,
debug_sec_print_rrset("Adding NX rrset: ", &q_rrset.rrset);
head = add_rrset2val_chain(mf, chain_p, &q_rrset.rrset, netreq);
/* On empty packet, find SOA (zonecut) for the qname */
if (head && GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0) {
val_chain_sched_soa(head, q_rrset.rrset.name);
return;
}
/* Insecure SOA indicating a zonecut in the authority section?
* Then schedule a DS query at the zonecut for insecure proof.
*/
n_soas = 0;
for ( i = _getdns_rrset_iter_init(&i_spc, pkt, pkt_len
, SECTION_AUTHORITY)
; i ; i = _getdns_rrset_iter_next(i)) {
rrset = _getdns_rrset_iter_value(i);
debug_sec_print_rrset("rrset: ", rrset);
if (rrset->rr_type != GETDNS_RRTYPE_SOA ||
_getdns_rrsig_iter_init(&rrsig_spc, rrset))
if (rrset->rr_type != GETDNS_RRTYPE_SOA)
continue;
n_soas += 1;
if (_getdns_rrsig_iter_init(&rrsig_spc, rrset))
continue;
val_chain_sched_ds(head, rrset->name);
}
/* No answer and no SOA indicating a zonecut? Find zonecut */
if (n_soas == 0)
val_chain_sched_ds(head, q_rrset.rrset.name);
}
@ -908,55 +908,6 @@ static getdns_dict *CD_extension(getdns_dns_req *dnsreq)
}
static void check_chain_complete(chain_head *chain);
static void val_chain_node_soa_cb(getdns_dns_req *dnsreq);
static void val_chain_sched_soa_node(chain_node *node)
{
getdns_context *context;
getdns_eventloop *loop;
char name[1024];
context = node->chains->netreq->owner->context;
loop = node->chains->netreq->owner->loop;
if (!gldns_wire2str_dname_buf(
(UNCONST_UINT8_p)node->ds.name, 256, name, sizeof(name)))
return;
DEBUG_SEC("schedule SOA lookup for %s\n", name);
node->lock++;
if (! node->soa_req &&
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_SOA,
CD_extension(node->chains->netreq->owner), node, &node->soa_req,
NULL, val_chain_node_soa_cb))
node->soa_req = NULL;
if (node->lock) node->lock--;
}
/* A SOA lookup is scheduled as a last resort. No signatures were found and
* no SOA in the authority section. If a SOA query returns an actual SOA
* answer, then a DS/DNSKEY lookup will follow the acquire the link of the
* authentication chain.
*/
static void val_chain_sched_soa(chain_head *head, const uint8_t *dname)
{
chain_node *node;
if (!head->netreq)
return;
if (!*dname)
return;
for ( node = head->parent
; node && !_dname_equal(dname, node->ds.name)
; node = node->parent);
if (node)
val_chain_sched_soa_node(node);
}
static chain_head *_dnskey_query(const chain_node *node)
{
@ -1145,60 +1096,13 @@ static void val_chain_node_cb(getdns_dns_req *dnsreq)
/* No signed DS and no signed proof of non-existance.
* Search further up the tree...
*/
val_chain_sched_soa_node(node->parent);
val_chain_sched_ds_node(node->parent);
if (node->lock) node->lock--;
check_chain_complete(node->chains);
}
static void val_chain_node_soa_cb(getdns_dns_req *dnsreq)
{
chain_node *node = (chain_node *)dnsreq->user_pointer;
getdns_network_req *netreq = dnsreq->netreqs[0];
_getdns_rrset_iter i_spc, *i;
_getdns_rrset *rrset;
/* A SOA query is always scheduled with a node as the user argument.
*/
assert(node != NULL);
for ( i = _getdns_rrset_iter_init(&i_spc, netreq->response
, netreq->response_len
, SECTION_ANSWER)
; i
; i = _getdns_rrset_iter_next(i)) {
rrset = _getdns_rrset_iter_value(i);
if (rrset->rr_type != GETDNS_RRTYPE_SOA)
continue;
while (node &&
! _dname_equal(node->ds.name, rrset->name))
node = node->parent;
if (node) {
node->lock++;
val_chain_sched_ds_node(node);
} else {
/* SOA for a different name */
node = (chain_node *)dnsreq->user_pointer;
if (node->parent) {
node->lock++;
val_chain_sched_soa_node(node->parent);
}
}
break;
}
if (!i && node->parent) {
node->lock++;
val_chain_sched_soa_node(node->parent);
}
if (node->lock) node->lock--;
check_chain_complete(node->chains);
}
/*************************** DNSSEC Validation *****************************
*****************************************************************************/
@ -2923,9 +2827,6 @@ static size_t count_outstanding_requests(chain_head *head)
if (!_getdns_netreq_finished(node->ds_req))
count++;
if (!_getdns_netreq_finished(node->soa_req))
count++;
}
return count + count_outstanding_requests(head->next);
}
@ -3433,12 +3334,6 @@ void _getdns_validation_chain_timeout(getdns_dns_req *dnsreq)
node->ds_req->owner);
node->ds_req = NULL;
}
if (!_getdns_netreq_finished(node->soa_req)) {
_getdns_context_cancel_request(
node->soa_req->owner);
node->soa_req = NULL;
}
}
head = next;
}
@ -3478,10 +3373,6 @@ void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq)
if (node->ds_req)
_getdns_context_cancel_request(
node->ds_req->owner);
if (node->soa_req)
_getdns_context_cancel_request(
node->soa_req->owner);
}
GETDNS_FREE(head->my_mf, head);
head = next;