mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-05-28 04:02:31 -04:00
DNAME support.
Changed answering algorithm so that DNAME is checked before wildcard and zone apex. (See query-processing-flowchart-200910-2.png.) Implemented CNAME from DNAME synthesis - quite dumb, with a lot of copying (because of ldns).
This commit is contained in:
parent
80c534cdc2
commit
9055f65fca
2 changed files with 102 additions and 28 deletions
|
|
@ -47,3 +47,6 @@ new-fast-box A 172.30.79.13
|
|||
|
||||
sub3 NS ns.sub2.example.com.
|
||||
sub4 NS ns.example.com.
|
||||
|
||||
d.example.com. CNAME non-existing.example.com.
|
||||
e.example.com. DNAME bogus25.com.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ static const uint8_t OPT_SIZE = 11;
|
|||
|
||||
static const int EDNS_ENABLED = 1;
|
||||
|
||||
static const uint32_t SYNTH_CNAME_TTL = 0;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Private functions */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
|
@ -330,8 +332,7 @@ void ns_put_answer( const zn_node *node, const ldns_rdf *name,
|
|||
debug_ns("Putting answers from node %s.\n", ldns_rdf2str(node->owner));
|
||||
if (type == LDNS_RR_TYPE_ANY) {
|
||||
ldns_rr_list *all = zn_all_rrsets(node);
|
||||
ns_put_rrset(all, name, LDNS_SECTION_ANSWER, 1,
|
||||
response, copied_rrs);
|
||||
ns_put_rrset(all, name, LDNS_SECTION_ANSWER, 1, response, copied_rrs);
|
||||
ldns_rr_list_free(all); // delete the list got from zn_all_rrsets()
|
||||
} else {
|
||||
ns_put_rrset(zn_find_rrset(node, type), name, LDNS_SECTION_ANSWER, 1,
|
||||
|
|
@ -538,6 +539,71 @@ void ns_answer_from_node( const zn_node *node, const zdb_zone *zone,
|
|||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
ldns_rr_list *ns_cname_from_dname( const ldns_rr_list *dname_rrset,
|
||||
const ldns_rdf *qname, ldns_rr_list *copied_rrs )
|
||||
{
|
||||
debug_ns("Synthetizing CNAME from DNAME...\n");
|
||||
// take only first dname RR
|
||||
ldns_rr *dname_rr = ldns_rr_list_rr(dname_rrset, 0);
|
||||
|
||||
ldns_rr *cname_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_CNAME);
|
||||
debug_ns("Creating CNAME with owner %s.\n", ldns_rdf2str(qname));
|
||||
ldns_rr_set_owner(cname_rr, ldns_rdf_clone(qname));
|
||||
ldns_rr_set_ttl(cname_rr, SYNTH_CNAME_TTL);
|
||||
|
||||
// copy the owner, replace last labels with DNAME
|
||||
// copying several times - no better way to do it in ldns
|
||||
ldns_rdf *tmp = ldns_dname_reverse(qname);
|
||||
assert(ldns_dname_label_count(tmp) >=
|
||||
ldns_dname_label_count(ldns_rr_owner(dname_rr)));
|
||||
ldns_rdf *tmp2 = ldns_dname_clone_from(tmp,
|
||||
ldns_dname_label_count(ldns_rr_owner(dname_rr)));
|
||||
ldns_rdf *cname = ldns_dname_reverse(tmp2);
|
||||
ldns_status s = ldns_dname_cat(cname, ldns_rr_rdf(dname_rr, 0));
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
ldns_rdf_deep_free(cname);
|
||||
ldns_rr_free(cname_rr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
debug_ns("CNAME canonical name: %s.\n", ldns_rdf2str(cname));
|
||||
|
||||
ldns_rr_set_rdf(cname_rr, cname, 0);
|
||||
ldns_rr_set_rd_count(cname_rr, 1);
|
||||
|
||||
ldns_rdf_deep_free(tmp);
|
||||
ldns_rdf_deep_free(tmp2);
|
||||
|
||||
ldns_rr_list *cname_rrset = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(cname_rrset, cname_rr);
|
||||
|
||||
ldns_rr_list_push_rr_list(copied_rrs, cname_rrset);
|
||||
|
||||
return cname_rrset;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void ns_process_dname( ldns_rr_list *dname_rrset, const ldns_rdf *qname,
|
||||
ldns_pkt *response, ldns_rr_list *copied_rrs )
|
||||
{
|
||||
debug_ns("Processing DNAME for owner %s...\n",
|
||||
ldns_rdf2str(ldns_rr_list_owner(dname_rrset)));
|
||||
// there should be only one DNAME
|
||||
assert(ldns_rr_list_rr_count(dname_rrset) == 1);
|
||||
// put the DNAME RRSet into the answer
|
||||
ns_try_put_rrset(dname_rrset, LDNS_SECTION_ANSWER, 1, response);
|
||||
// synthetize CNAME (no way to tell that client supports DNAME)
|
||||
ldns_rr_list *synth_cname = ns_cname_from_dname(dname_rrset, qname,
|
||||
copied_rrs);
|
||||
ns_try_put_rrset(synth_cname, LDNS_SECTION_ANSWER, 1, response);
|
||||
ldns_rr_list_free(synth_cname);
|
||||
ldns_pkt_set_rcode(response, LDNS_RCODE_NOERROR);
|
||||
// do not search for the name in new zone (out-of-bailiwick)
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void ns_answer( zdb_database *zdb, const ldns_rr *question, ldns_pkt *response,
|
||||
ldns_rr_list *copied_rrs )
|
||||
{
|
||||
|
|
@ -609,35 +675,40 @@ search:
|
|||
debug_ns("Found node with name: %s (rest of QNAME: %s).\n",
|
||||
ldns_rdf2str(node->owner), ldns_rdf2str(qname));
|
||||
|
||||
// try to find a wildcard child
|
||||
ldns_rdf *wildcard = ldns_dname_new_frm_str("*");
|
||||
if (ldns_dname_cat(wildcard, qname) != LDNS_STATUS_OK) {
|
||||
log_error("Unknown error occured.\n");
|
||||
ldns_pkt_set_rcode(response, LDNS_RCODE_SERVFAIL);
|
||||
ldns_rdf_deep_free(wildcard);
|
||||
ldns_rdf_deep_free(qname);
|
||||
return; // need some return value??
|
||||
}
|
||||
|
||||
const zn_node *wildcard_node = zdb_find_name_in_zone(zone, wildcard);
|
||||
if (wildcard_node != NULL) {
|
||||
debug_ns("Found wildcard node %s, answering.\n", ldns_rdf2str(
|
||||
wildcard_node->owner));
|
||||
ns_answer_from_node(wildcard_node, zone, ldns_rr_owner(question),
|
||||
ldns_rr_get_type(question), response,
|
||||
copied_rrs);
|
||||
} else if (zone->apex == node) {
|
||||
// if we ended in the zone apex, the name is not in the zone
|
||||
ns_put_authority_soa(zone, response);
|
||||
ldns_pkt_set_rcode(response, LDNS_RCODE_NXDOMAIN);
|
||||
// check if DNAME is present
|
||||
ldns_rr_list *dname_rrset = NULL;
|
||||
if ((dname_rrset = zn_find_rrset(node, LDNS_RR_TYPE_DNAME)) != NULL) {
|
||||
ns_process_dname(dname_rrset, ldns_rr_owner(question), response,
|
||||
copied_rrs);
|
||||
} else {
|
||||
debug_ns("DNAME not implemented yet.\n");
|
||||
// try to find a wildcard child
|
||||
ldns_rdf *wildcard = ldns_dname_new_frm_str("*");
|
||||
if (ldns_dname_cat(wildcard, qname) != LDNS_STATUS_OK) {
|
||||
log_error("Unknown error occured.\n");
|
||||
ldns_pkt_set_rcode(response, LDNS_RCODE_SERVFAIL);
|
||||
ldns_rdf_deep_free(wildcard);
|
||||
ldns_rdf_deep_free(qname);
|
||||
return; // need some return value??
|
||||
}
|
||||
|
||||
// continue searching for the new qname
|
||||
goto search;
|
||||
//ldns_pkt_set_rcode(response, LDNS_RCODE_NXDOMAIN);
|
||||
const zn_node *wildcard_node =
|
||||
zdb_find_name_in_zone(zone, wildcard);
|
||||
if (wildcard_node != NULL) {
|
||||
debug_ns("Found wildcard node %s, answering.\n", ldns_rdf2str(
|
||||
wildcard_node->owner));
|
||||
ns_answer_from_node(
|
||||
wildcard_node, zone, ldns_rr_owner(question),
|
||||
ldns_rr_get_type(question), response, copied_rrs);
|
||||
} else if (zone->apex == node) {
|
||||
// if we ended in the zone apex, the name is not in the zone
|
||||
ns_put_authority_soa(zone, response);
|
||||
ldns_pkt_set_rcode(response, LDNS_RCODE_NXDOMAIN);
|
||||
} else {
|
||||
// continue searching for the new qname
|
||||
goto search;
|
||||
}
|
||||
ldns_rdf_deep_free(wildcard);
|
||||
}
|
||||
ldns_rdf_deep_free(wildcard);
|
||||
}
|
||||
|
||||
ldns_rdf_deep_free(qname);
|
||||
|
|
|
|||
Loading…
Reference in a new issue