Skip to content

Commit df029dd

Browse files
committed
Return DELEG only with EDNS DE bit set
1 parent 7ad8528 commit df029dd

File tree

6 files changed

+93
-9
lines changed

6 files changed

+93
-9
lines changed

dns.h

+7
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ typedef enum rr_section rr_section_type;
5757
#define RCODE_NOTAUTH 9 /* server not authoritative */
5858
#define RCODE_NOTZONE 10 /* name not inside zone */
5959

60+
/* DNSKEY FLAGS */
61+
62+
/* #define DNSKEY_FLAG_ZONE (1 << (15 - 7)) */
63+
/* #define DNSKEY_FLAG_REVOKE (1 << (15 - 8)) */
64+
#define DNSKEY_FLAG_DELEG (1 << (15 - 14))
65+
/* #define DNSKEY_FLAG_SEP (1 << (15 - 15)) */
66+
6067
/* Standardized NSD return code. Partially maps to DNS RCODE values. */
6168
enum nsd_rc
6269
{

edns.c

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ edns_init_record(edns_record_type *edns)
6969
edns->maxlen = 0;
7070
edns->opt_reserved_space = 0;
7171
edns->dnssec_ok = 0;
72+
edns->deleg_ok = 0;
7273
edns->nsid = 0;
7374
edns->zoneversion = 0;
7475
edns->cookie_status = COOKIE_NOT_PRESENT;
@@ -190,6 +191,7 @@ edns_parse_record(edns_record_type *edns, buffer_type *packet,
190191
edns->status = EDNS_OK;
191192
edns->maxlen = opt_class;
192193
edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
194+
edns->deleg_ok = opt_flags & DELEG_OK_MASK;
193195
return 1;
194196
}
195197

edns.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ struct query;
2121
#define COOKIE_CODE 10 /* COOKIE option code */
2222
#define EDE_CODE 15 /* Extended DNS Errors option code */
2323
#define ZONEVERSION_CODE 19 /* ZONEVERSION option code */
24-
#define DNSSEC_OK_MASK 0x8000U /* do bit mask */
24+
#define DNSSEC_OK_MASK 0x8000U /* DO bit mask */
25+
#define COMPACT_ANSWER_OK_MASK 0x4000U /* DO bit mask */
26+
#define DELEG_OK_MASK 0x2000U /* DE bit mask (DELEG) */
2527

2628
/* https://iana.org/assignments/dns-parameters/#zoneversion-type-values */
2729
#define ZONEVERSION_SOA_SERIAL 0
@@ -62,6 +64,7 @@ struct edns_record
6264
size_t maxlen;
6365
size_t opt_reserved_space;
6466
int dnssec_ok;
67+
int deleg_ok;
6568
int nsid;
6669
int zoneversion;
6770
cookie_status_type cookie_status;

namedb.c

+60-2
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,60 @@ domain_find_parent_zone(namedb_type* db, zone_type* zone)
577577
}
578578

579579
domain_type *
580-
domain_find_delegation_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns, rrset_type **deleg)
580+
domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns)
581581
{
582-
/* return highest NS and/or DELEG RRsets in the zone that is a delegation above */
582+
/* return highest NS RRset in the zone that is a delegation above */
583583
domain_type* result = NULL;
584584
rrset_type* rrset = NULL;
585+
while (domain && domain != zone->apex) {
586+
rrset = domain_find_rrset(domain, zone, TYPE_NS);
587+
if (rrset) {
588+
*ns = rrset;
589+
result = domain;
590+
}
591+
domain = domain->parent;
592+
}
593+
594+
if(result)
595+
return result;
596+
597+
*ns = NULL;
598+
return NULL;
599+
}
600+
601+
int
602+
zone_is_deleg_zone(zone_type* zone)
603+
{
604+
rrset_type* dnskey_set;
605+
uint16_t i;
606+
607+
if(!zone || !zone->apex
608+
|| !(dnskey_set = domain_find_rrset(zone->apex, zone, TYPE_DNSKEY)))
609+
return 0;
610+
for(i = 0; i < dnskey_set->rr_count; i++) {
611+
if(dnskey_set->rrs[i].rdata_count > 0
612+
&& rdata_atom_size(dnskey_set->rrs[i].rdatas[0])
613+
== sizeof(uint16_t)
614+
&& read_uint16(rdata_atom_data(dnskey_set->rrs[i].rdatas[0]))
615+
& DNSKEY_FLAG_DELEG)
616+
return 1;
617+
}
618+
return 0;
619+
}
620+
621+
domain_type *
622+
domain_find_delegation_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns, rrset_type **deleg)
623+
{
624+
/* return highest NS and/or DELEG RRsets in the zone that is a delegation above */
625+
domain_type* result;
626+
rrset_type* rrset;
627+
if(!zone_is_deleg_zone(zone)) {
628+
if(deleg)
629+
*deleg = NULL;
630+
return domain_find_ns_rrsets(domain, zone, ns);
631+
}
632+
result = NULL;
633+
rrset = NULL;
585634
while (domain && domain != zone->apex) {
586635
if ((rrset = domain_find_rrset(domain, zone, TYPE_NS))) {
587636
*ns = rrset;
@@ -617,6 +666,15 @@ find_dname_above(domain_type* domain, zone_type* zone)
617666

618667
int
619668
domain_is_glue(domain_type* domain, zone_type* zone)
669+
{
670+
rrset_type* unused;
671+
domain_type* ns_domain = domain_find_ns_rrsets(domain, zone, &unused);
672+
return (ns_domain != NULL &&
673+
domain_find_rrset(ns_domain, zone, TYPE_SOA) == NULL);
674+
}
675+
676+
int
677+
domain_is_glue_DE(domain_type* domain, zone_type* zone)
620678
{
621679
rrset_type* unused;
622680
domain_type* ns_domain = domain_find_delegation_rrsets(domain, zone, &unused, &unused);

namedb.h

+3
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,14 @@ rrset_type* domain_find_any_rrset(domain_type* domain, zone_type* zone);
260260
zone_type* domain_find_zone(namedb_type* db, domain_type* domain);
261261
zone_type* domain_find_parent_zone(namedb_type* db, zone_type* zone);
262262

263+
domain_type* domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns);
264+
int zone_is_deleg_zone(zone_type* zone);
263265
domain_type* domain_find_delegation_rrsets(
264266
domain_type* domain, zone_type* zone, rrset_type **ns, rrset_type **deleg);
265267
/* find DNAME rrset in domain->parent or higher and return that domain */
266268
domain_type * find_dname_above(domain_type* domain, zone_type* zone);
267269

270+
int domain_is_glue_DE(domain_type* domain, zone_type* zone);
268271
int domain_is_glue(domain_type* domain, zone_type* zone);
269272

270273
rrset_type* domain_find_non_cname_rrset(domain_type* domain, zone_type* zone);

query.c

+17-6
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,9 @@ add_additional_rrsets(struct query *query, answer_type *answer,
696696

697697
assert(additional);
698698

699-
if (!allow_glue && domain_is_glue(match, query->zone))
699+
if (!allow_glue && ( query->edns.deleg_ok
700+
? domain_is_glue_DE(match, query->zone)
701+
: domain_is_glue(match, query->zone)))
700702
continue;
701703

702704
/*
@@ -947,12 +949,12 @@ answer_delegation(query_type *query, answer_type *answer)
947949
ds_found = 1;
948950

949951
}
950-
if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_DELEG))) {
952+
if (query->deleg_rrset) {
951953
add_rrset(query, answer, AUTHORITY_SECTION,
952-
query->delegation_domain, rrset);
954+
query->delegation_domain, query->deleg_rrset);
953955
deleg_found = 1;
954956
}
955-
if (ds_found && deleg_found) {
957+
if (ds_found && (!query->edns.deleg_ok || deleg_found)) {
956958
; /* pass; No NSEC needed showing the absence of the other RRset */
957959
#ifdef NSEC3
958960
} else if (query->zone->nsec3_param) {
@@ -1507,8 +1509,17 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer,
15071509
}
15081510
answer_nodata(q, answer, closest_encloser);
15091511
} else {
1510-
q->delegation_domain = domain_find_delegation_rrsets(
1511-
closest_encloser, q->zone, &q->delegation_rrset, &q->deleg_rrset);
1512+
if(q->edns.deleg_ok)
1513+
q->delegation_domain =domain_find_delegation_rrsets(
1514+
closest_encloser, q->zone,
1515+
&q->delegation_rrset, &q->deleg_rrset);
1516+
else {
1517+
q->deleg_rrset = NULL;
1518+
q->delegation_domain =domain_find_ns_rrsets(
1519+
closest_encloser, q->zone,
1520+
&q->delegation_rrset);
1521+
}
1522+
15121523
if(q->delegation_domain && find_dname_above(q->delegation_domain, q->zone)) {
15131524
q->delegation_domain = NULL; /* use higher DNAME */
15141525
}

0 commit comments

Comments
 (0)