/** * Print ixfr. * */ 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; }
/** * Update serial. * */ ods_status zone_update_serial(zone_type* zone) { ods_status status = ODS_STATUS_OK; rrset_type* rrset = NULL; rr_type* soa = NULL; ldns_rr* rr = NULL; ldns_rdf* soa_rdata = NULL; ods_log_assert(zone); ods_log_assert(zone->apex); ods_log_assert(zone->name); ods_log_assert(zone->db); ods_log_assert(zone->signconf); if (zone->db->serial_updated) { /* already done, unmark and return ok */ ods_log_debug("[%s] zone %s soa serial already up to date", zone_str, zone->name); zone->db->serial_updated = 0; return ODS_STATUS_OK; } rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA); ods_log_assert(rrset); ods_log_assert(rrset->rrs); ods_log_assert(rrset->rrs[0].rr); rr = ldns_rr_clone(rrset->rrs[0].rr); if (!rr) { ods_log_error("[%s] unable to update zone %s soa serial: failed to " "clone soa rr", zone_str, zone->name); return ODS_STATUS_ERR; } status = namedb_update_serial(zone->db, zone->signconf->soa_serial, zone->db->inbserial); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to update zone %s soa serial: %s", zone_str, zone->name, ods_status2str(status)); ldns_rr_free(rr); return status; } ods_log_verbose("[%s] zone %s set soa serial to %u", zone_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 update zone %s soa serial: failed to " "replace soa serial rdata", zone_str, zone->name); ldns_rr_free(rr); return ODS_STATUS_ERR; } soa = rrset_add_rr(rrset, rr); ods_log_assert(soa); rrset_diff(rrset, 0, 0); zone->db->serial_updated = 0; return ODS_STATUS_OK; }
/** * Publish the NSEC3 parameters as indicated by the signer configuration. * */ ods_status zone_publish_nsec3param(zone_type* zone) { rrset_type* rrset = NULL; rr_type* n3prr = NULL; ldns_rr* rr = NULL; ods_status status = ODS_STATUS_OK; if (!zone || !zone->name || !zone->db || !zone->signconf) { return ODS_STATUS_ASSERT_ERR; } if (!zone->signconf->nsec3params) { /* NSEC */ ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC); return ODS_STATUS_OK; } if (!zone->signconf->nsec3params->rr) { rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS); if (!rr) { ods_log_error("[%s] unable to publish nsec3params for zone %s: " "error creating rr (%s)", zone_str, zone->name, ods_status2str(status)); return ODS_STATUS_MALLOC_ERR; } ldns_rr_set_class(rr, zone->klass); ldns_rr_set_ttl(rr, 0); ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex)); ldns_nsec3_add_param_rdfs(rr, zone->signconf->nsec3params->algorithm, 0, zone->signconf->nsec3params->iterations, zone->signconf->nsec3params->salt_len, zone->signconf->nsec3params->salt_data); /** * Always set bit 7 of the flags to zero, * according to rfc5155 section 11 */ ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0); zone->signconf->nsec3params->rr = rr; } ods_log_assert(zone->signconf->nsec3params->rr); status = zone_add_rr(zone, zone->signconf->nsec3params->rr, 0); if (status == ODS_STATUS_UNCHANGED) { /* rr already exists, adjust pointer */ rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS); ods_log_assert(rrset); n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr); ods_log_assert(n3prr); if (n3prr->rr != zone->signconf->nsec3params->rr) { ldns_rr_free(zone->signconf->nsec3params->rr); } zone->signconf->nsec3params->rr = n3prr->rr; status = ODS_STATUS_OK; } else if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to publish nsec3params for zone %s: " "error adding nsec3params (%s)", zone_str, zone->name, ods_status2str(status)); } return status; }
/** * Query response. * */ static query_state query_response(query_type* q, ldns_rr_type qtype) { rrset_type* rrset = NULL; response_type r; if (!q || !q->zone) { return QUERY_DISCARDED; } r.rrset_count = 0; lock_basic_lock(&q->zone->zone_lock); rrset = zone_lookup_rrset(q->zone, q->zone->apex, qtype); if (rrset) { if (!response_add_rrset(&r, rrset, LDNS_SECTION_ANSWER)) { lock_basic_unlock(&q->zone->zone_lock); return query_servfail(q); } /* NS RRset goes into Authority Section */ rrset = zone_lookup_rrset(q->zone, q->zone->apex, LDNS_RR_TYPE_NS); if (rrset) { if (!response_add_rrset(&r, rrset, LDNS_SECTION_AUTHORITY)) { lock_basic_unlock(&q->zone->zone_lock); return query_servfail(q); } } } else if (qtype != LDNS_RR_TYPE_SOA) { rrset = zone_lookup_rrset(q->zone, q->zone->apex, LDNS_RR_TYPE_SOA); if (rrset) { if (!response_add_rrset(&r, rrset, LDNS_SECTION_AUTHORITY)) { lock_basic_unlock(&q->zone->zone_lock); return query_servfail(q); } } } else { lock_basic_unlock(&q->zone->zone_lock); return query_servfail(q); } lock_basic_unlock(&q->zone->zone_lock); response_encode(q, &r); /* compression */ return QUERY_PROCESSED; }
/** * Print axfr. * */ 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; }
/** * Unlink NSEC3PARAM RR. * */ void zone_rollback_nsec3param(zone_type* zone) { rrset_type* rrset = NULL; rr_type* n3prr = NULL; if (!zone || !zone->signconf || !zone->signconf->nsec3params) { return; } rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS); if (rrset && zone->signconf->nsec3params->rr) { n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr); if (n3prr && !n3prr->exists && n3prr->rr == zone->signconf->nsec3params->rr) { zone->signconf->nsec3params->rr = NULL; } } return; }
/** * Send notifies. * */ static void dnsout_send_notify(void* zone) { zone_type* z = (zone_type*) zone; rrset_type* rrset = NULL; ldns_rr* soa = NULL; if (!z || !z->notify) { ods_log_error("[%s] unable to send notify for zone %s: no notify " "handler", adapter_str, z->name); return; } ods_log_assert(z->adoutbound); ods_log_assert(z->adoutbound->config); ods_log_assert(z->adoutbound->type == ADAPTER_DNS); ods_log_assert(z->db); ods_log_assert(z->name); ods_log_debug("[%s] enable notify for zone %s serial %u", adapter_str, z->name, z->db->intserial); rrset = zone_lookup_rrset(z, z->apex, LDNS_RR_TYPE_SOA); ods_log_assert(rrset); soa = ldns_rr_clone(rrset->rrs[0].rr); notify_enable(z->notify, soa); return; }
/** * Unlink DNSKEY RRs. * */ void zone_rollback_dnskeys(zone_type* zone) { uint16_t i = 0; rrset_type* rrset = NULL; rr_type* dnskey = NULL; if (!zone || !zone->signconf || !zone->signconf->keys) { return; } rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY); /* unlink dnskey rrs */ for (i=0; i < zone->signconf->keys->count; i++) { if (rrset && zone->signconf->keys->keys[i].dnskey) { dnskey = rrset_lookup_rr(rrset, zone->signconf->keys->keys[i].dnskey); if (dnskey && !dnskey->exists && dnskey->rr == zone->signconf->keys->keys[i].dnskey) { zone->signconf->keys->keys[i].dnskey = NULL; } } } /* done */ return; }
/** * Read namedb from backup file. * */ ods_status backup_read_namedb(FILE* in, void* zone) { zone_type* z = (zone_type*) zone; denial_type* denial = NULL; rrset_type* rrset = NULL; ods_status result = ODS_STATUS_OK; ldns_rr_type type_covered; ldns_rr* rr = NULL; ldns_rdf* prev = NULL; ldns_rdf* orig = NULL; ldns_rdf* dname = NULL; ldns_status status = LDNS_STATUS_OK; char line[SE_ADFILE_MAXLINE]; char* str = NULL; char* locator = NULL; uint32_t flags = 0; unsigned int l = 0; ods_log_assert(in); ods_log_assert(z); /* $ORIGIN <zone name> */ dname = adapi_get_origin(z); if (!dname) { ods_log_error("[%s] error getting default value for $ORIGIN", backup_str); return ODS_STATUS_ERR; } orig = ldns_rdf_clone(dname); if (!orig) { ods_log_error("[%s] error setting default value for $ORIGIN", backup_str); return ODS_STATUS_ERR; } /* read RRs */ ods_log_debug("[%s] read RRs %s", backup_str, z->name); while ((rr = backup_read_rr(in, z, line, &orig, &prev, &status, &l)) != NULL) { /* check status */ if (status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RR #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; goto backup_namedb_done; } /* add to the database */ result = adapi_add_rr(z, rr, 1); if (result == ODS_STATUS_UNCHANGED) { ods_log_debug("[%s] skipping RR #%i (duplicate): %s", backup_str, l, line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_OK; continue; } else if (result != ODS_STATUS_OK) { ods_log_error("[%s] error adding RR #%i: %s", backup_str, l, line); ldns_rr_free(rr); rr = NULL; goto backup_namedb_done; } } if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RR #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; goto backup_namedb_done; } namedb_diff(z->db, 0, 0); /* read NSEC(3)s */ ods_log_debug("[%s] read NSEC(3)s %s", backup_str, z->name); l = 0; while ((rr = backup_read_rr(in, z, line, &orig, &prev, &status, &l)) != NULL) { /* check status */ if (status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading NSEC(3) #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; goto backup_namedb_done; } if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_NSEC && ldns_rr_get_type(rr) != LDNS_RR_TYPE_NSEC3) { ods_log_error("[%s] error NSEC(3) #%i is not NSEC(3): %s", backup_str, l, line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_namedb_done; } /* add to the denial chain */ denial = namedb_lookup_denial(z->db, ldns_rr_owner(rr)); if (!denial) { ods_log_error("[%s] error adding NSEC(3) #%i: %s", backup_str, l, line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_namedb_done; } denial_add_rr(denial, rr); } if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading NSEC(3) #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; goto backup_namedb_done; } /* read RRSIGs */ ods_log_debug("[%s] read RRSIGs %s", backup_str, z->name); l = 0; while ((rr = backup_read_rr(in, z, line, &orig, &prev, &status, &l)) != NULL) { /* check status */ if (status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RRSIG #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; goto backup_namedb_done; } if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { ods_log_error("[%s] error RRSIG #%i is not RRSIG: %s", backup_str, l, line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_namedb_done; } /* read locator and flags */ str = strstr(line, "flags"); if (str) { flags = (uint32_t) atoi(str+6); } str = strstr(line, "locator"); if (str) { locator = replace_space_with_nul(str+8); } /* add signatures */ type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); if (type_covered == LDNS_RR_TYPE_NSEC || type_covered == LDNS_RR_TYPE_NSEC3) { denial = namedb_lookup_denial(z->db, ldns_rr_owner(rr)); if (!denial) { ods_log_error("[%s] error restoring RRSIG #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_namedb_done; } rrset = denial->rrset; } else { rrset = zone_lookup_rrset(z, ldns_rr_owner(rr), type_covered); } if (!rrset || !rrset_add_rrsig(rrset, rr, locator, flags)) { ods_log_error("[%s] error restoring RRSIG #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_namedb_done; } else { rrset->needs_signing = 0; } } if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RRSIG #%i (%s): %s", backup_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; } backup_namedb_done: if (orig) { ldns_rdf_deep_free(orig); orig = NULL; } if (prev) { ldns_rdf_deep_free(prev); prev = NULL; } return result; }
/** * Publish the keys as indicated by the signer configuration. * */ ods_status zone_publish_dnskeys(zone_type* zone) { hsm_ctx_t* ctx = NULL; uint32_t ttl = 0; uint16_t i = 0; ods_status status = ODS_STATUS_OK; rrset_type* rrset = NULL; rr_type* dnskey = NULL; if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) { return ODS_STATUS_ASSERT_ERR; } ods_log_assert(zone->name); /* hsm access */ ctx = hsm_create_context(); if (ctx == NULL) { ods_log_error("[%s] unable to publish keys for zone %s: " "error creating libhsm context", zone_str, zone->name); return ODS_STATUS_HSM_ERR; } /* dnskey ttl */ ttl = zone->default_ttl; if (zone->signconf->dnskey_ttl) { ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl); } /* publish keys */ for (i=0; i < zone->signconf->keys->count; i++) { if (!zone->signconf->keys->keys[i].publish) { continue; } if (!zone->signconf->keys->keys[i].dnskey) { /* get dnskey */ status = lhsm_get_key(ctx, zone->apex, &zone->signconf->keys->keys[i]); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to publish dnskeys for zone %s: " "error creating dnskey", zone_str, zone->name); break; } } ods_log_assert(zone->signconf->keys->keys[i].dnskey); ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl); ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass); status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0); if (status == ODS_STATUS_UNCHANGED) { /* rr already exists, adjust pointer */ rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY); ods_log_assert(rrset); dnskey = rrset_lookup_rr(rrset, zone->signconf->keys->keys[i].dnskey); ods_log_assert(dnskey); if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) { ldns_rr_free(zone->signconf->keys->keys[i].dnskey); } zone->signconf->keys->keys[i].dnskey = dnskey->rr; status = ODS_STATUS_OK; } else if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to publish dnskeys for zone %s: " "error adding dnskey", zone_str, zone->name); break; } } /* done */ hsm_destroy_context(ctx); return status; }