domain.c
Go to the documentation of this file.
/*
* Copyright (c) 2009 NLNet Labs. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include "log.h"
#include "signer/backup.h"
#include "signer/denial.h"
#include "signer/domain.h"
#include "signer/ixfr.h"
#include "signer/zone.h"
static const char* dname_str = "domain";
void
log_dname(ldns_rdf *rdf, const char* pre, int level)
{
char* str = NULL;
if (ods_log_get_level() < level) {
return;
}
str = ldns_rdf2str(rdf);
if (!str) {
return;
}
if (level == LOG_EMERG) {
ods_fatal_exit("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_ALERT) {
ods_log_alert("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_CRIT) {
ods_log_crit("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_ERR) {
ods_log_error("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_WARNING) {
ods_log_warning("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_NOTICE) {
ods_log_info("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_INFO) {
ods_log_verbose("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_DEBUG) {
ods_log_debug("[%s] %s: %s", dname_str, pre?pre:"", str);
} else if (level == LOG_DEEEBUG) {
ods_log_deeebug("[%s] %s: %s", dname_str, pre?pre:"", str);
} else {
ods_log_deeebug("[%s] %s: %s", dname_str, pre?pre:"", str);
}
free((void*)str);
}
domain_type*
domain_create(zone_type* zone, ldns_rdf* dname)
{
domain_type* domain = NULL;
if (!dname || !zone) {
return NULL;
}
CHECKALLOC(domain = (domain_type*) malloc(sizeof(domain_type)));
domain->dname = ldns_rdf_clone(dname);
if (!domain->dname) {
ods_log_error("[%s] unable to create domain: ldns_rdf_clone() "
"failed", dname_str);
free(domain);
return NULL;
}
domain->zone = zone;
domain->denial = NULL; /* no reference yet */
domain->node = NULL; /* not in db yet */
domain->rrsets = NULL;
domain->parent = NULL;
domain->is_apex = 0;
domain->is_new = 0;
return domain;
}
size_t
domain_count_rrset_is_added(domain_type* domain)
{
rrset_type* rrset = NULL;
size_t count = 0;
if (!domain) {
return 0;
}
rrset = domain->rrsets;
while (rrset) {
if (rrset_count_rr_is_added(rrset)) {
count++;
}
rrset = rrset->next;
}
return count;
}
rrset_type*
domain_lookup_rrset(domain_type* domain, ldns_rr_type rrtype)
{
rrset_type* rrset = NULL;
if (!domain || !domain->rrsets || !rrtype) {
return NULL;
}
rrset = domain->rrsets;
while (rrset && rrset->rrtype != rrtype) {
rrset = rrset->next;
}
return rrset;
}
void
domain_add_rrset(domain_type* domain, rrset_type* rrset)
{
rrset_type** p = NULL;
denial_type* denial = NULL;
ods_log_assert(domain);
ods_log_assert(rrset);
if (!domain->rrsets) {
domain->rrsets = rrset;
} else {
p = &domain->rrsets;
while(*p) {
p = &((*p)->next);
}
*p = rrset;
rrset->next = NULL;
}
log_rrset(domain->dname, rrset->rrtype, "+RRSET", LOG_DEEEBUG);
rrset->domain = (void*) domain;
if (domain->denial) {
denial = (denial_type*) domain->denial;
denial->bitmap_changed = 1;
}
}
void
domain_diff(domain_type* domain, unsigned is_ixfr, unsigned more_coming)
{
denial_type* denial = NULL;
rrset_type* rrset = NULL;
rrset_type* prev_rrset = NULL;
if (!domain) {
return;
}
rrset = domain->rrsets;
while (rrset) {
if (rrset->rrtype == LDNS_RR_TYPE_NSEC3PARAMS ||
rrset->rrtype == LDNS_RR_TYPE_DNSKEY) {
/* always do full diff on NSEC3PARAMS | DNSKEY RRset */
rrset_diff(rrset, 0, more_coming);
} else {
rrset_diff(rrset, is_ixfr, more_coming);
}
if (rrset->rr_count <= 0) {
/* delete entire rrset */
if (!prev_rrset) {
domain->rrsets = rrset->next;
} else {
prev_rrset->next = rrset->next;
}
rrset->next = NULL;
log_rrset(domain->dname, rrset->rrtype, "-RRSET", LOG_DEEEBUG);
rrset_cleanup(rrset);
if (!prev_rrset) {
rrset = domain->rrsets;
} else {
rrset = prev_rrset->next;
}
if (domain->denial) {
denial = (denial_type*) domain->denial;
denial->bitmap_changed = 1;
}
} else {
/* just go to next rrset */
prev_rrset = rrset;
rrset = rrset->next;
}
}
}
void
domain_rollback(domain_type* domain, int keepsc)
{
denial_type* denial = NULL;
rrset_type* rrset = NULL;
rrset_type* prev_rrset = NULL;
int del_rrset = 0;
uint16_t i = 0;
if (!domain) {
return;
}
rrset = domain->rrsets;
while (rrset) {
if (keepsc) {
/* skip rollback for NSEC3PARAM and DNSKEY RRset */
if (rrset->rrtype == LDNS_RR_TYPE_NSEC3PARAMS ||
rrset->rrtype == LDNS_RR_TYPE_DNSKEY) {
prev_rrset = rrset;
rrset = rrset->next;
continue;
}
}
/* walk rrs */
for (i=0; i < rrset->rr_count; i++) {
rrset->rrs[i].is_added = 0;
rrset->rrs[i].is_removed = 0;
if (!rrset->rrs[i].exists) {
/* can we delete the RRset? */
if(rrset->rr_count == 1) {
del_rrset = 1;
}
rrset_del_rr(rrset, i);
i--;
}
}
/* next rrset */
if (del_rrset) {
/* delete entire rrset */
if (!prev_rrset) {
domain->rrsets = rrset->next;
} else {
prev_rrset->next = rrset->next;
}
rrset->next = NULL;
log_rrset(domain->dname, rrset->rrtype, "-RRSET", LOG_DEEEBUG);
rrset_cleanup(rrset);
if (!prev_rrset) {
rrset = domain->rrsets;
} else {
rrset = prev_rrset->next;
}
if (domain->denial) {
denial = (denial_type*) domain->denial;
denial->bitmap_changed = 0;
}
del_rrset = 0;
} else {
/* just go to next rrset */
prev_rrset = rrset;
rrset = rrset->next;
}
}
}
int
domain_ent2unsignedns(domain_type* domain)
{
ldns_rbnode_t* n = LDNS_RBTREE_NULL;
domain_type* d = NULL;
ods_log_assert(domain);
if (domain->rrsets) {
return 0; /* not an empty non-terminal */
}
n = ldns_rbtree_next(domain->node);
while (n && n != LDNS_RBTREE_NULL) {
d = (domain_type*) n->data;
if (!ldns_dname_is_subdomain(d->dname, domain->dname)) {
break;
}
if (d->rrsets) {
if (domain_is_delegpt(d) != LDNS_RR_TYPE_NS &&
domain_is_occluded(d) == LDNS_RR_TYPE_SOA) {
/* domain has signed delegation/auth */
return 0;
}
}
/* maybe there is data at the next domain */
n = ldns_rbtree_next(n);
}
return 1;
}
ldns_rr_type
domain_is_delegpt(domain_type* domain)
{
ods_log_assert(domain);
if (domain->is_apex) {
return LDNS_RR_TYPE_SOA;
}
if (domain_lookup_rrset(domain, LDNS_RR_TYPE_NS)) {
if (domain_lookup_rrset(domain, LDNS_RR_TYPE_DS)) {
/* Signed delegation */
return LDNS_RR_TYPE_DS;
} else {
/* Unsigned delegation */
return LDNS_RR_TYPE_NS;
}
}
/* Authoritative */
return LDNS_RR_TYPE_SOA;
}
ldns_rr_type
domain_is_occluded(domain_type* domain)
{
domain_type* parent = NULL;
ods_log_assert(domain);
if (domain->is_apex) {
return LDNS_RR_TYPE_SOA;
}
parent = domain->parent;
while (parent && !parent->is_apex) {
if (domain_lookup_rrset(parent, LDNS_RR_TYPE_NS)) {
/* Glue / Empty non-terminal to Glue */
return LDNS_RR_TYPE_A;
}
if (domain_lookup_rrset(parent, LDNS_RR_TYPE_DNAME)) {
/* Occluded data / Empty non-terminal to Occluded data */
return LDNS_RR_TYPE_DNAME;
}
parent = parent->parent;
}
/* Authoritative or delegation */
return LDNS_RR_TYPE_SOA;
}
void
domain_print(FILE* fd, domain_type* domain, ods_status* status)
{
char* str = NULL;
rrset_type* rrset = NULL;
rrset_type* soa_rrset = NULL;
rrset_type* cname_rrset = NULL;
if (!domain || !fd) {
if (status) {
ods_log_crit("[%s] unable to print domain: domain or fd missing",
dname_str);
*status = ODS_STATUS_ASSERT_ERR;
}
return;
}
/* empty non-terminal? */
if (!domain->rrsets) {
str = ldns_rdf2str(domain->dname);
fprintf(fd, ";;Empty non-terminal %s\n", str);
free((void*)str);
/* Denial of Existence */
if (domain->denial) {
denial_print(fd, (denial_type*) domain->denial, status);
}
return;
}
/* no other data may accompany a CNAME */
cname_rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_CNAME);
if (cname_rrset) {
rrset_print(fd, cname_rrset, 0, status);
} else {
/* if SOA, print soa first */
if (domain->is_apex) {
soa_rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
if (soa_rrset) {
rrset_print(fd, soa_rrset, 0, status);
if (status && *status != ODS_STATUS_OK) {
return;
}
}
}
/* print other RRsets */
rrset = domain->rrsets;
while (rrset) {
/* skip SOA RRset */
if (rrset->rrtype != LDNS_RR_TYPE_SOA) {
rrset_print(fd, rrset, 0, status);
}
if (status && *status != ODS_STATUS_OK) {
ods_log_crit("[%s] failed to print one or more RRsets: %s",
dname_str, ods_status2str(*status));
return;
}
rrset = rrset->next;
}
}
/* Denial of Existence */
if (domain->denial) {
denial_print(fd, (denial_type*) domain->denial, status);
}
}
void
domain_cleanup(domain_type* domain)
{
if (!domain) {
return;
}
ldns_rdf_deep_free(domain->dname);
rrset_cleanup(domain->rrsets);
free(domain);
}
void
domain_backup2(FILE* fd, domain_type* domain, int sigs)
{
rrset_type* rrset = NULL;
if (!domain || !fd) {
return;
}
/* if SOA, print soa first */
if (domain->is_apex) {
rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
if (rrset) {
if (sigs) {
rrset_backup2(fd, rrset);
} else {
rrset_print(fd, rrset, 1, NULL);
}
}
}
rrset = domain->rrsets;
while (rrset) {
/* skip SOA RRset */
if (rrset->rrtype != LDNS_RR_TYPE_SOA) {
if (sigs) {
rrset_backup2(fd, rrset);
} else {
rrset_print(fd, rrset, 1, NULL);
}
}
rrset = rrset->next;
}
}
domain_count_rrset_is_added
size_t domain_count_rrset_is_added(domain_type *domain)
Definition: domain.c:118
domain_cleanup
void domain_cleanup(domain_type *domain)
Definition: domain.c:465
rrset_struct::rr_count
size_t rr_count
Definition: rrset.h:65
domain_add_rrset
void domain_add_rrset(domain_type *domain, rrset_type *rrset)
Definition: domain.c:160
rrset_cleanup
void rrset_cleanup(rrset_type *rrset)
Definition: rrset.c:925
domain_backup2
void domain_backup2(FILE *fd, domain_type *domain, int sigs)
Definition: domain.c:481
domain_lookup_rrset
rrset_type * domain_lookup_rrset(domain_type *domain, ldns_rr_type rrtype)
Definition: domain.c:141
domain_print
void domain_print(FILE *fd, domain_type *domain, ods_status *status)
Definition: domain.c:398
rrset_count_rr_is_added
size_t rrset_count_rr_is_added(rrset_type *rrset)
Definition: rrset.c:278
zone_struct
Definition: zone.h:60
rrset_struct::rrtype
ldns_rr_type rrtype
Definition: rrset.h:63
rrset_struct::next
rrset_type * next
Definition: rrset.h:60
domain_diff
void domain_diff(domain_type *domain, unsigned is_ixfr, unsigned more_coming)
Definition: domain.c:190
denial.h
domain_struct::denial
denial_type * denial
Definition: domain.h:53
rr_struct::exists
unsigned exists
Definition: rrset.h:54
domain_struct::parent
domain_type * parent
Definition: domain.h:57
denial_struct
Definition: denial.h:50
domain_ent2unsignedns
int domain_ent2unsignedns(domain_type *domain)
Definition: domain.c:310
rr_struct::is_removed
unsigned is_removed
Definition: rrset.h:56
log_rrset
void log_rrset(ldns_rdf *dname, ldns_rr_type type, const char *pre, int level)
Definition: rrset.c:99
denial_print
void denial_print(FILE *fd, denial_type *denial, ods_status *status)
Definition: denial.c:331
domain_is_delegpt
ldns_rr_type domain_is_delegpt(domain_type *domain)
Definition: domain.c:344
domain_is_occluded
ldns_rr_type domain_is_occluded(domain_type *domain)
Definition: domain.c:369
domain_struct
Definition: domain.h:52
domain_create
domain_type * domain_create(zone_type *zone, ldns_rdf *dname)
Definition: domain.c:88
log_dname
void log_dname(ldns_rdf *rdf, const char *pre, int level)
Definition: domain.c:48
domain_struct::is_apex
unsigned is_apex
Definition: domain.h:60
rrset_backup2
void rrset_backup2(FILE *fd, rrset_type *rrset)
Definition: rrset.c:948
domain_struct::is_new
unsigned is_new
Definition: domain.h:59
rrset_del_rr
void rrset_del_rr(rrset_type *rrset, uint16_t rrnum)
Definition: rrset.c:334
domain_struct::zone
zone_type * zone
Definition: domain.h:54
rrset_struct::domain
domain_type * domain
Definition: rrset.h:62
backup.h
zone.h
rrset_struct
Definition: rrset.h:59
domain.h
domain_struct::node
ldns_rbnode_t * node
Definition: domain.h:55
domain_rollback
void domain_rollback(domain_type *domain, int keepsc)
Definition: domain.c:241
rrset_diff
void rrset_diff(rrset_type *rrset, unsigned is_ixfr, unsigned more_coming)
Definition: rrset.c:366
domain_struct::rrsets
rrset_type * rrsets
Definition: domain.h:58
ixfr.h
denial_struct::bitmap_changed
unsigned bitmap_changed
Definition: denial.h:56
rr_struct::is_added
unsigned is_added
Definition: rrset.h:55
rrset_print
void rrset_print(FILE *fd, rrset_type *rrset, int skip_rrsigs, ods_status *status)
Definition: rrset.c:868
domain_struct::dname
ldns_rdf * dname
Definition: domain.h:56
rrset_struct::rrs
rr_type * rrs
Definition: rrset.h:64