adapi.c
Go to the documentation of this file.
/*
* Copyright (c) 2009-2011 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 "adapter/adapi.h"
#include "duration.h"
#include "log.h"
#include "status.h"
#include "util.h"
#include "signer/zone.h"
#include <ldns/ldns.h>
static const char* adapi_str = "adapter";
uint32_t
adapi_get_serial(zone_type* zone)
{
if (!zone || !zone->db) {
return 0;
}
return zone->db->inbserial;
}
void
adapi_set_serial(zone_type* zone, uint32_t serial)
{
if (!zone || !zone->db) {
return;
}
zone->db->inbserial = serial;
}
ldns_rdf*
adapi_get_origin(zone_type* zone)
{
if (!zone) {
return NULL;
}
return zone->apex;
}
uint32_t
adapi_get_ttl(zone_type* zone)
{
if (!zone) {
return 0;
}
return zone->default_ttl;
}
/*
* Do full zone transaction.
*
*/
void
adapi_trans_full(zone_type* zone, unsigned more_coming)
{
time_t start = 0;
time_t end = 0;
uint32_t num_added = 0;
if (!zone || !zone->db) {
return;
}
namedb_diff(zone->db, 0, more_coming);
if (zone->stats) {
pthread_mutex_lock(&zone->stats->stats_lock);
zone->stats->nsec_time = 0;
zone->stats->nsec_count = 0;
pthread_mutex_unlock(&zone->stats->stats_lock);
}
start = time(NULL);
/* nsecify(3) */
namedb_nsecify(zone->db, &num_added);
end = time(NULL);
if (zone->stats) {
pthread_mutex_lock(&zone->stats->stats_lock);
if (!zone->stats->start_time) {
zone->stats->start_time = start;
}
zone->stats->nsec_time = (end-start);
zone->stats->nsec_count = num_added;
pthread_mutex_unlock(&zone->stats->stats_lock);
}
}
/*
* Do incremental zone transaction.
*
*/
void
adapi_trans_diff(zone_type* zone, unsigned more_coming)
{
time_t start = 0;
time_t end = 0;
uint32_t num_added = 0;
if (!zone || !zone->db) {
return;
}
namedb_diff(zone->db, 1, more_coming);
if (zone->stats) {
pthread_mutex_lock(&zone->stats->stats_lock);
zone->stats->nsec_time = 0;
zone->stats->nsec_count = 0;
pthread_mutex_unlock(&zone->stats->stats_lock);
}
start = time(NULL);
/* nsecify(3) */
namedb_nsecify(zone->db, &num_added);
end = time(NULL);
if (zone->stats) {
pthread_mutex_lock(&zone->stats->stats_lock);
if (!zone->stats->start_time) {
zone->stats->start_time = start;
}
zone->stats->nsec_time = (end-start);
zone->stats->nsec_count = num_added;
pthread_mutex_unlock(&zone->stats->stats_lock);
}
}
static ods_status
adapi_process_soa(zone_type* zone, ldns_rr* rr, int add, int backup)
{
uint32_t tmp = 0;
ldns_rdf* soa_rdata = NULL;
ods_status status = ODS_STATUS_OK;
ods_log_assert(rr);
ods_log_assert(zone);
ods_log_assert(zone->name);
ods_log_assert(zone->signconf);
if (backup) {
/* no need to do processing */
return ODS_STATUS_OK;
}
if (zone->signconf->soa_ttl) {
tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
ods_log_verbose("[%s] zone %s set soa ttl to %u",
adapi_str, zone->name, tmp);
ldns_rr_set_ttl(rr, tmp);
}
if (zone->signconf->soa_min) {
tmp = (uint32_t) duration2time(zone->signconf->soa_min);
ods_log_verbose("[%s] zone %s set soa minimum to %u",
adapi_str, zone->name, tmp);
soa_rdata = ldns_rr_set_rdf(rr,
ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
SE_SOA_RDATA_MINIMUM);
if (soa_rdata) {
ldns_rdf_deep_free(soa_rdata);
soa_rdata = NULL;
} else {
ods_log_error("[%s] unable to %s soa to zone %s: failed to replace "
"soa minimum rdata", adapi_str, add?"add":"delete",
zone->name);
return ODS_STATUS_ASSERT_ERR;
}
}
if (!add) {
/* we are done */
return ODS_STATUS_OK;
}
tmp = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
status = namedb_update_serial(zone->db, zone->name,
zone->signconf->soa_serial, tmp);
if (status != ODS_STATUS_OK) {
ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
"soa serial rdata (%s)", adapi_str, zone->name,
ods_status2str(status));
if (status == ODS_STATUS_CONFLICT_ERR) {
ods_log_error("[%s] If this is the result of a key rollover, "
"please increment the serial in the unsigned zone %s",
adapi_str, zone->name);
}
return status;
}
ods_log_verbose("[%s] zone %s set soa serial to %u", adapi_str,
zone->name, zone->db->intserial);
soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
zone->db->intserial), SE_SOA_RDATA_SERIAL);
if (soa_rdata) {
ldns_rdf_deep_free(soa_rdata);
soa_rdata = NULL;
} else {
ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
"soa serial rdata", adapi_str, zone->name);
return ODS_STATUS_ERR;
}
zone->db->serial_updated = 1;
return ODS_STATUS_OK;
}
static void
adapi_process_dnskey(zone_type* zone, ldns_rr* rr)
{
uint32_t tmp = 0;
ods_log_assert(rr);
ods_log_assert(zone);
ods_log_assert(zone->name);
ods_log_assert(zone->signconf);
tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
ods_log_verbose("[%s] zone %s set dnskey ttl to %u",
adapi_str, zone->name, tmp);
ldns_rr_set_ttl(rr, tmp);
}
static ods_status
adapi_process_rr(zone_type* zone, ldns_rr* rr, int add, int backup)
{
ods_status status = ODS_STATUS_OK;
uint32_t tmp = 0;
ods_log_assert(rr);
ods_log_assert(zone);
ods_log_assert(zone->name);
ods_log_assert(zone->db);
ods_log_assert(zone->signconf);
/* We only support IN class */
if (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) {
ods_log_warning("[%s] only class in is supported, changing class "
"to in", adapi_str);
ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
}
/* RR processing */
if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) {
ods_log_error("[%s] unable to %s rr to zone: soa record has "
"invalid owner name", adapi_str, add?"add":"delete");
return ODS_STATUS_ERR;
}
status = adapi_process_soa(zone, rr, add, backup);
if (status != ODS_STATUS_OK) {
ods_log_error("[%s] unable to %s rr: failed to process soa "
"record", adapi_str, add?"add":"delete");
return status;
}
} else {
if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex) &&
!ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->apex)) {
ods_log_warning("[%s] zone %s contains out-of-zone data, "
"skipping", adapi_str, zone->name);
return ODS_STATUS_UNCHANGED;
} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY) {
adapi_process_dnskey(zone, rr);
} else if (util_is_dnssec_rr(rr) && !backup) {
ods_log_warning("[%s] zone %s contains dnssec data (type=%u), "
"skipping", adapi_str, zone->name,
(unsigned) ldns_rr_get_type(rr));
return ODS_STATUS_UNCHANGED;
} else if (zone->signconf->max_zone_ttl) {
/* Convert MaxZoneTTL */
tmp = (uint32_t) duration2time(zone->signconf->max_zone_ttl);
}
}
/* //MaxZoneTTL. Only set for RRtype != SOA && RRtype != DNSKEY */
if (tmp && tmp < ldns_rr_ttl(rr)) {
char* str = ldns_rdf2str(ldns_rr_owner(rr));
if (str) {
str[(strlen(str))-1] = '\0';
/* replace tabs with white space */
for (int i = 0; i < strlen(str); i++) {
if (str[i] == '\t') {
str[i] = ' ';
}
}
ods_log_warning("[%s] TTL %u exceeds MaxZoneTTL %u for rrset "
"<%s,%s>", adapi_str, ldns_rr_ttl(rr), tmp, str,
rrset_type2str(ldns_rr_get_type(rr)));
LDNS_FREE(str);
}
}
/* TODO: DNAME and CNAME checks */
/* TODO: NS and DS checks */
if (add) {
return zone_add_rr(zone, rr, 1);
} else {
return zone_del_rr(zone, rr, 1);
}
/* not reached */
return ODS_STATUS_ERR;
}
ods_status
adapi_add_rr(zone_type* zone, ldns_rr* rr, int backup)
{
return adapi_process_rr(zone, rr, 1, backup);
}
ods_status
adapi_del_rr(zone_type* zone, ldns_rr* rr, int backup)
{
return adapi_process_rr(zone, rr, 0, backup);
}
ods_status
adapi_printzone(FILE* fd, zone_type* zone)
{
ods_status status = ODS_STATUS_OK;
if (!fd || !zone || !zone->db) {
ods_log_error("[%s] unable to print zone: file descriptor, zone or "
"name database missing", adapi_str);
return ODS_STATUS_ASSERT_ERR;
}
namedb_export(fd, zone->db, &status);
return status;
}
ods_status
adapi_printaxfr(FILE* fd, zone_type* zone)
{
rrset_type* rrset = NULL;
ods_status status = ODS_STATUS_OK;
if (!fd || !zone || !zone->db) {
ods_log_error("[%s] unable to print axfr: file descriptor, zone or "
"name database missing", adapi_str);
return ODS_STATUS_ASSERT_ERR;
}
namedb_export(fd, zone->db, &status);
if (status == ODS_STATUS_OK) {
rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
ods_log_assert(rrset);
rrset_print(fd, rrset, 1, &status);
}
return status;
}
ods_status
adapi_printixfr(FILE* fd, zone_type* zone)
{
rrset_type* rrset = NULL;
ods_status status = ODS_STATUS_OK;
if (!fd || !zone || !zone->db || !zone->ixfr) {
ods_log_error("[%s] unable to print ixfr: file descriptor, zone or "
"name database missing", adapi_str);
return ODS_STATUS_ASSERT_ERR;
}
if (!zone->db->is_initialized) {
/* no ixfr yet */
return ODS_STATUS_OK;
}
rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
ods_log_assert(rrset);
rrset_print(fd, rrset, 1, &status);
if (status != ODS_STATUS_OK) {
return status;
}
pthread_mutex_lock(&zone->ixfr->ixfr_lock);
if (ixfr_print(fd, zone->ixfr)) {
zone->adoutbound->error = 1;
}
pthread_mutex_unlock(&zone->ixfr->ixfr_lock);
rrset_print(fd, rrset, 1, &status);
return status;
}
zone_struct::default_ttl
uint32_t default_ttl
Definition: zone.h:63
ixfr_struct::ixfr_lock
pthread_mutex_t ixfr_lock
Definition: ixfr.h:64
namedb_struct::intserial
uint32_t intserial
Definition: namedb.h:54
namedb_export
void namedb_export(FILE *fd, namedb_type *db, ods_status *status)
Definition: namedb.c:1025
adapi_get_serial
uint32_t adapi_get_serial(zone_type *zone)
Definition: adapi.c:50
rrset_type2str
const char * rrset_type2str(ldns_rr_type type)
Definition: rrset.c:158
signconf_struct::soa_min
duration_type * soa_min
Definition: signconf.h:67
signconf_struct::soa_serial
const char * soa_serial
Definition: signconf.h:68
signconf_struct::soa_ttl
duration_type * soa_ttl
Definition: signconf.h:66
zone_struct
Definition: zone.h:60
adapi.h
adapter_struct::error
unsigned error
Definition: adapter.h:63
namedb_update_serial
ods_status namedb_update_serial(namedb_type *db, const char *zone_name, const char *format, uint32_t inbound_serial)
Definition: namedb.c:193
namedb_diff
void namedb_diff(namedb_type *db, unsigned is_ixfr, unsigned more_coming)
Definition: namedb.c:811
stats_struct::nsec_time
time_t nsec_time
Definition: stats.h:55
zone_struct::adoutbound
adapter_type * adoutbound
Definition: zone.h:75
stats_struct::nsec_count
uint32_t nsec_count
Definition: stats.h:54
namedb_nsecify
void namedb_nsecify(namedb_type *db, uint32_t *num_added)
Definition: namedb.c:872
adapi_set_serial
void adapi_set_serial(zone_type *zone, uint32_t serial)
Definition: adapi.c:64
zone_struct::db
namedb_type * db
Definition: zone.h:79
zone_struct::ixfr
ixfr_type * ixfr
Definition: zone.h:80
namedb_struct::inbserial
uint32_t inbserial
Definition: namedb.h:53
namedb_struct::serial_updated
unsigned serial_updated
Definition: namedb.h:58
namedb_struct::is_initialized
unsigned is_initialized
Definition: namedb.h:57
signconf_struct::max_zone_ttl
duration_type * max_zone_ttl
Definition: signconf.h:70
zone_struct::signconf
signconf_type * signconf
Definition: zone.h:77
stats_struct::start_time
time_t start_time
Definition: stats.h:61
adapi_get_origin
ldns_rdf * adapi_get_origin(zone_type *zone)
Definition: adapi.c:78
zone_add_rr
ods_status zone_add_rr(zone_type *zone, ldns_rr *rr, int do_stats)
Definition: zone.c:531
ixfr_print
int ixfr_print(FILE *fd, ixfr_type *ixfr)
Definition: ixfr.c:216
adapi_printzone
ods_status adapi_printzone(FILE *fd, zone_type *zone)
Definition: adapi.c:381
adapi_del_rr
ods_status adapi_del_rr(zone_type *zone, ldns_rr *rr, int backup)
Definition: adapi.c:370
zone_del_rr
ods_status zone_del_rr(zone_type *zone, ldns_rr *rr, int do_stats)
Definition: zone.c:613
zone.h
zone_lookup_rrset
rrset_type * zone_lookup_rrset(zone_type *zone, ldns_rdf *owner, ldns_rr_type type)
Definition: zone.c:512
adapi_trans_full
void adapi_trans_full(zone_type *zone, unsigned more_coming)
Definition: adapi.c:106
adapi_printixfr
ods_status adapi_printixfr(FILE *fd, zone_type *zone)
Definition: adapi.c:423
signconf_struct::dnskey_ttl
duration_type * dnskey_ttl
Definition: signconf.h:62
adapi_add_rr
ods_status adapi_add_rr(zone_type *zone, ldns_rr *rr, int backup)
Definition: adapi.c:359
zone_struct::name
const char * name
Definition: zone.h:69
rrset_struct
Definition: rrset.h:59
adapi_get_ttl
uint32_t adapi_get_ttl(zone_type *zone)
Definition: adapi.c:92
stats_struct::stats_lock
pthread_mutex_t stats_lock
Definition: stats.h:63
adapi_printaxfr
ods_status adapi_printaxfr(FILE *fd, zone_type *zone)
Definition: adapi.c:399
zone_struct::apex
ldns_rdf * apex
Definition: zone.h:61
rrset_print
void rrset_print(FILE *fd, rrset_type *rrset, int skip_rrsigs, ods_status *status)
Definition: rrset.c:868
zone_struct::stats
stats_type * stats
Definition: zone.h:85
adapi_trans_diff
void adapi_trans_diff(zone_type *zone, unsigned more_coming)
Definition: adapi.c:143