uint32_t zonefile_get_serial(struct zonefile *z) { ldns_rdf *rdf = ldns_rr_rdf(z->rr_soa, 2); assert(rdf != NULL); return (ldns_rdf2native_int32(rdf)); }
struct zversion_t* zversion_read(struct zone_entry_t* entry, uint32_t serial) { const char* fn = zinfo_ixfr_name(entry, serial); struct zversion_t* v; FILE* in = fopen(fn, "ra"); ldns_status status; ldns_rr* rr = 0; uint32_t dttl = 3600; ldns_rdf* origin = 0, *prev = 0; int line_nr = 1; if(!in) { perror(fn); return NULL; } v = (struct zversion_t*)calloc(1, sizeof(*v)); if(!v) { fclose(in); printf("out of memory\n"); return NULL; } v->serial = serial; v->ixfr = ldns_rr_list_new(); while(!feof(in)) { status = ldns_rr_new_frm_fp_l(&rr, in, &dttl, &origin, &prev, &line_nr); if(status == LDNS_STATUS_SYNTAX_TTL || status == LDNS_STATUS_SYNTAX_ORIGIN || status == LDNS_STATUS_SYNTAX_EMPTY) continue; if(status != LDNS_STATUS_OK) { printf("error %s:%d: %s\n", fn, line_nr, ldns_get_errorstr_by_id(status)); fclose(in); ldns_rdf_deep_free(origin); ldns_rdf_deep_free(prev); ldns_rr_list_deep_free(v->ixfr); free(v); return NULL; } ldns_rr_list_push_rr(v->ixfr, rr); } ldns_rdf_deep_free(origin); ldns_rdf_deep_free(prev); fclose(in); if(ldns_rr_list_rr_count(v->ixfr) < 1 || ldns_rr_get_type(ldns_rr_list_rr(v->ixfr, 0)) != LDNS_RR_TYPE_SOA) { printf("invalid IXFR format in %s\n", fn); ldns_rr_list_deep_free(v->ixfr); free(v); return NULL; } v->next_serial = ldns_rdf2native_int32(ldns_rr_rdf( ldns_rr_list_rr(v->ixfr, 0), 2)); return v; }
/** get authority section SOA serial value */ static uint32_t get_serial(ldns_pkt* p) { ldns_rr *rr = ldns_rr_list_rr(ldns_pkt_authority(p), 0); ldns_rdf *rdf; uint32_t val; if(!rr) return 0; rdf = ldns_rr_rdf(rr, 2); if(!rdf) return 0; val = ldns_rdf2native_int32(rdf); verbose(3, "found serial %u in msg. ", (int)val); return val; }
void ldns_rr_soa_increment_func_data(ldns_rr *soa, ldns_soa_serial_increment_func_t f, void *data) { ldns_rdf *prev_soa_serial_rdf; if ( !soa || !f || ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA || !ldns_rr_rdf(soa, 2)) { return; } prev_soa_serial_rdf = ldns_rr_set_rdf( soa , ldns_native2rdf_int32( LDNS_RDF_TYPE_INT32 , (*f)( ldns_rdf2native_int32( ldns_rr_rdf(soa, 2)) , data ) ) , 2 ); LDNS_FREE(prev_soa_serial_rdf); }
ldns_status ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { ldns_rbnode_t *first_name_node; ldns_rbnode_t *current_name_node; ldns_dnssec_name *current_name; ldns_status result = LDNS_STATUS_OK; ldns_rr *nsec_rr; ldns_rr_list *nsec3_list; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; if (!zone || !new_rrs || !zone->names) { return LDNS_STATUS_ERR; } /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf( soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } nsec3_list = ldns_rr_list_new(); first_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); current_name_node = first_name_node; while (current_name_node && current_name_node != LDNS_RBTREE_NULL) { current_name = (ldns_dnssec_name *) current_name_node->data; nsec_rr = ldns_dnssec_create_nsec3(current_name, NULL, zone->soa->name, algorithm, flags, iterations, salt_length, salt); /* by default, our nsec based generator adds rrsigs * remove the bitmap for empty nonterminals */ if (!current_name->rrsets) { ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr)); } ldns_rr_set_ttl(nsec_rr, nsec_ttl); ldns_dnssec_name_add_rr(current_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); ldns_rr_list_push_rr(nsec3_list, nsec_rr); current_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(current_name_node)); } ldns_rr_list_sort_nsec3(nsec3_list); ldns_dnssec_chain_nsec3_list(nsec3_list); if (result != LDNS_STATUS_OK) { return result; } ldns_rr_list_free(nsec3_list); return result; }
ldns_status ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs) { ldns_rbnode_t *first_node, *cur_node, *next_node; ldns_dnssec_name *cur_name, *next_name; ldns_rr *nsec_rr; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf( soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } first_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); cur_node = first_node; if (cur_node) { next_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(cur_node)); } else { next_node = NULL; } while (cur_node && next_node) { cur_name = (ldns_dnssec_name *)cur_node->data; next_name = (ldns_dnssec_name *)next_node->data; nsec_rr = ldns_dnssec_create_nsec(cur_name, next_name, LDNS_RR_TYPE_NSEC); ldns_rr_set_ttl(nsec_rr, nsec_ttl); ldns_dnssec_name_add_rr(cur_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); cur_node = next_node; if (cur_node) { next_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(cur_node)); } } if (cur_node && !next_node) { cur_name = (ldns_dnssec_name *)cur_node->data; next_name = (ldns_dnssec_name *)first_node->data; nsec_rr = ldns_dnssec_create_nsec(cur_name, next_name, LDNS_RR_TYPE_NSEC); ldns_rr_set_ttl(nsec_rr, nsec_ttl); ldns_dnssec_name_add_rr(cur_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); } else { printf("error\n"); } return LDNS_STATUS_OK; }
/** * Read ixfr journal from file. * * */ ods_status backup_read_ixfr(FILE* in, void* zone) { zone_type* z = (zone_type*) zone; ods_status result = ODS_STATUS_OK; 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]; uint32_t serial = 0; unsigned l = 0; unsigned first_soa = 1; /* expect soa first */ unsigned del_mode = 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 */ 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_ixfr_done; } if (first_soa == 2) { ods_log_error("[%s] bad ixfr journal: trailing RRs after final " "SOA", backup_str); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_ixfr_done; } if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { serial = ldns_rdf2native_int32( ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); if (first_soa) { ods_log_debug("[%s] ixfr first SOA: %s", backup_str, ldns_rr2str(rr)); /* first SOA */ ldns_rr_free(rr); rr = NULL; if (z->db->outserial != serial) { ods_log_error("[%s] bad ixfr journal: first SOA wrong " "serial (was %u, expected %u)", backup_str, serial, z->db->outserial); result = ODS_STATUS_ERR; goto backup_ixfr_done; } first_soa = 0; continue; } ods_log_assert(!first_soa); if (!del_mode) { if (z->db->outserial == serial) { /* final SOA */ ods_log_debug("[%s] ixfr final SOA: %s", backup_str, ldns_rr2str(rr)); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_OK; first_soa = 2; continue; } else { ods_log_debug("[%s] new part SOA: %s", backup_str, ldns_rr2str(rr)); lock_basic_lock(&z->ixfr->ixfr_lock); ixfr_purge(z->ixfr); lock_basic_unlock(&z->ixfr->ixfr_lock); } } else { ods_log_debug("[%s] second part SOA: %s", backup_str, ldns_rr2str(rr)); } del_mode = !del_mode; } /* ixfr add or del rr */ if (first_soa) { ods_log_error("[%s] bad ixfr journal: first RR not SOA", backup_str); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; goto backup_ixfr_done; } ods_log_assert(!first_soa); lock_basic_lock(&z->ixfr->ixfr_lock); if (del_mode) { ods_log_debug("[%s] -IXFR: %s", backup_str, ldns_rr2str(rr)); ixfr_del_rr(z->ixfr, rr); } else { ods_log_debug("[%s] +IXFR: %s", backup_str, ldns_rr2str(rr)); ixfr_add_rr(z->ixfr, rr); } lock_basic_unlock(&z->ixfr->ixfr_lock); } 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; } backup_ixfr_done: if (orig) { ldns_rdf_deep_free(orig); orig = NULL; } if (prev) { ldns_rdf_deep_free(prev); prev = NULL; } return result; }
/** * Read zone file. * */ static ods_status adfile_read_file(FILE* fd, zone_type* zone) { ods_status result = ODS_STATUS_OK; ldns_rr* rr = NULL; ldns_rdf* prev = NULL; ldns_rdf* orig = NULL; ldns_rdf* dname = NULL; uint32_t ttl = 0; uint32_t new_serial = 0; ldns_status status = LDNS_STATUS_OK; char line[SE_ADFILE_MAXLINE]; unsigned int line_update_interval = 100000; unsigned int line_update = line_update_interval; unsigned int l = 0; ods_log_assert(fd); ods_log_assert(zone); /* $ORIGIN <zone name> */ dname = adapi_get_origin(zone); if (!dname) { ods_log_error("[%s] error getting default value for $ORIGIN", adapter_str); return ODS_STATUS_ERR; } orig = ldns_rdf_clone(dname); if (!orig) { ods_log_error("[%s] error setting default value for $ORIGIN", adapter_str); return ODS_STATUS_ERR; } /* $TTL <default ttl> */ ttl = adapi_get_ttl(zone); /* read RRs */ while ((rr = adfile_read_rr(fd, zone, line, &orig, &prev, &ttl, &status, &l)) != NULL) { /* check status */ if (status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RR at line %i (%s): %s", adapter_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; break; } /* debug update */ if (l > line_update) { ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line); line_update += line_update_interval; } /* SOA? */ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { new_serial = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); } /* add to the database */ result = adapi_add_rr(zone, rr, 0); if (result == ODS_STATUS_UNCHANGED) { ods_log_debug("[%s] skipping RR at line %i (duplicate): %s", adapter_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 at line %i: %s", adapter_str, l, line); ldns_rr_free(rr); rr = NULL; break; } } /* and done */ if (orig) { ldns_rdf_deep_free(orig); orig = NULL; } if (prev) { ldns_rdf_deep_free(prev); prev = NULL; } if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RR at line %i (%s): %s", adapter_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; } /* input zone ok, set inbound serial and apply differences */ if (result == ODS_STATUS_OK) { result = namedb_examine(zone->db); if (result != ODS_STATUS_OK) { ods_log_error("[%s] unable to read file: zonefile contains errors", adapter_str); return result; } adapi_set_serial(zone, new_serial); } return result; }
/** * Process SOA. * */ 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 ldns_status ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, ldns_rbtree_t **map) { ldns_rbnode_t *first_name_node; ldns_rbnode_t *current_name_node; ldns_dnssec_name *current_name; ldns_status result = LDNS_STATUS_OK; ldns_rr *nsec_rr; ldns_rr_list *nsec3_list; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; ldns_rbnode_t *hashmap_node; if (!zone || !new_rrs || !zone->names) { return LDNS_STATUS_ERR; } /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr && ldns_rr_rdf(soa->rrs->rr, 6) != NULL) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } if (zone->hashed_names) { ldns_traverse_postorder(zone->hashed_names, ldns_hashed_names_node_free, NULL); LDNS_FREE(zone->hashed_names); } zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); if (zone->hashed_names && map) { *map = zone->hashed_names; } first_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); current_name_node = first_name_node; while (current_name_node && current_name_node != LDNS_RBTREE_NULL && result == LDNS_STATUS_OK) { current_name = (ldns_dnssec_name *) current_name_node->data; nsec_rr = ldns_dnssec_create_nsec3(current_name, NULL, zone->soa->name, algorithm, flags, iterations, salt_length, salt); /* by default, our nsec based generator adds rrsigs * remove the bitmap for empty nonterminals */ if (!current_name->rrsets) { ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr)); } ldns_rr_set_ttl(nsec_rr, nsec_ttl); result = ldns_dnssec_name_add_rr(current_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); if (ldns_rr_owner(nsec_rr)) { hashmap_node = LDNS_MALLOC(ldns_rbnode_t); if (hashmap_node == NULL) { return LDNS_STATUS_MEM_ERR; } current_name->hashed_name = ldns_dname_label(ldns_rr_owner(nsec_rr), 0); if (current_name->hashed_name == NULL) { LDNS_FREE(hashmap_node); return LDNS_STATUS_MEM_ERR; } hashmap_node->key = current_name->hashed_name; hashmap_node->data = current_name; if (! ldns_rbtree_insert(zone->hashed_names , hashmap_node)) { LDNS_FREE(hashmap_node); } } current_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(current_name_node)); } if (result != LDNS_STATUS_OK) { return result; } /* Make sorted list of nsec3s (via zone->hashed_names) */ nsec3_list = ldns_rr_list_new(); if (nsec3_list == NULL) { return LDNS_STATUS_MEM_ERR; } for ( hashmap_node = ldns_rbtree_first(zone->hashed_names) ; hashmap_node != LDNS_RBTREE_NULL ; hashmap_node = ldns_rbtree_next(hashmap_node) ) { current_name = (ldns_dnssec_name *) hashmap_node->data; nsec_rr = ((ldns_dnssec_name *) hashmap_node->data)->nsec; if (nsec_rr) { ldns_rr_list_push_rr(nsec3_list, nsec_rr); } } result = ldns_dnssec_chain_nsec3_list(nsec3_list); ldns_rr_list_free(nsec3_list); return result; }
/** * Read IXFR from file. * */ static ods_status addns_read_file(FILE* fd, zone_type* zone) { ldns_rr* rr = NULL; uint32_t new_serial = 0; uint32_t old_serial = 0; uint32_t tmp_serial = 0; ldns_rdf* prev = NULL; ldns_rdf* orig = NULL; ldns_rdf* dname = NULL; uint32_t ttl = 0; size_t rr_count = 0; ods_status result = ODS_STATUS_OK; ldns_status status = LDNS_STATUS_OK; char line[SE_ADFILE_MAXLINE]; unsigned is_axfr = 0; unsigned del_mode = 0; unsigned soa_seen = 0; unsigned line_update_interval = 100000; unsigned line_update = line_update_interval; unsigned l = 0; ods_log_assert(fd); ods_log_assert(zone); /* $ORIGIN <zone name> */ dname = adapi_get_origin(zone); if (!dname) { ods_log_error("[%s] error getting default value for $ORIGIN", adapter_str); return ODS_STATUS_ERR; } orig = ldns_rdf_clone(dname); if (!orig) { ods_log_error("[%s] error setting default value for $ORIGIN", adapter_str); return ODS_STATUS_ERR; } /* $TTL <default ttl> */ ttl = adapi_get_ttl(zone); /* read RRs */ while ((rr = addns_read_rr(fd, line, &orig, &prev, &ttl, &status, &l)) != NULL) { /* check status */ if (status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RR at line %i (%s): %s", adapter_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; break; } /* debug update */ if (l > line_update) { ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line); line_update += line_update_interval; } /* first RR: check if SOA and correct zone & serialno */ if (rr_count == 0) { rr_count++; if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) { ods_log_error("[%s] bad xfr, first rr is not soa", adapter_str); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; break; } soa_seen++; if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) { ods_log_error("[%s] bad xfr, soa dname not equal to zone " "dname %s", adapter_str, zone->name); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; break; } tmp_serial = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); old_serial = adapi_get_serial(zone); if (!util_serial_gt(tmp_serial, old_serial)) { ods_log_info("[%s] zone %s is already up to date, have " "serial %u, got serial %u", adapter_str, zone->name, old_serial, tmp_serial); new_serial = tmp_serial; ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_UNCHANGED; break; } ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_OK; continue; } /* second RR: if not soa, this is an AXFR */ if (rr_count == 1) { if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) { ods_log_verbose("[%s] detected axfr serial=%u for zone %s", adapter_str, tmp_serial, zone->name); new_serial = tmp_serial; is_axfr = 1; del_mode = 0; } else { ods_log_verbose("[%s] detected ixfr serial=%u for zone %s", adapter_str, tmp_serial, zone->name); new_serial = tmp_serial; tmp_serial = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); ldns_rr_free(rr); rr = NULL; rr_count++; if (tmp_serial < new_serial) { del_mode = 1; result = ODS_STATUS_OK; continue; } else { ods_log_error("[%s] bad xfr for zone %s, bad soa serial", adapter_str, zone->name); result = ODS_STATUS_ERR; break; } } } /* soa means swap */ rr_count++; if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { if (!is_axfr) { tmp_serial = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); if (tmp_serial <= new_serial) { if (tmp_serial == new_serial) { soa_seen++; } del_mode = !del_mode; ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_OK; continue; } else { ods_log_assert(tmp_serial > new_serial); ods_log_error("[%s] bad xfr for zone %s, bad soa serial", adapter_str, zone->name); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_ERR; break; } } else { /* for axfr */ soa_seen++; } } /* [add to/remove from] the zone */ if (!is_axfr && del_mode) { ods_log_debug("[%s] delete RR #%i at line %i: %s", adapter_str, rr_count, l, line); result = adapi_del_rr(zone, rr, 0); ldns_rr_free(rr); rr = NULL; } else { ods_log_debug("[%s] add RR #%i at line %i: %s", adapter_str, rr_count, l, line); result = adapi_add_rr(zone, rr, 0); } if (result == ODS_STATUS_UNCHANGED) { ods_log_debug("[%s] skipping RR at line %i (%s): %s", adapter_str, l, del_mode?"not found":"duplicate", line); ldns_rr_free(rr); rr = NULL; result = ODS_STATUS_OK; continue; } else if (result != ODS_STATUS_OK) { ods_log_error("[%s] error %s RR at line %i: %s", adapter_str, del_mode?"deleting":"adding", l, line); ldns_rr_free(rr); rr = NULL; break; } } /* and done */ if (orig) { ldns_rdf_deep_free(orig); orig = NULL; } if (prev) { ldns_rdf_deep_free(prev); prev = NULL; } if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) { ods_log_error("[%s] error reading RR at line %i (%s): %s", adapter_str, l, ldns_get_errorstr_by_id(status), line); result = ODS_STATUS_ERR; } /* check the number of SOAs seen */ if (result == ODS_STATUS_OK) { if ((is_axfr && soa_seen != 2) || (!is_axfr && soa_seen != 3)) { ods_log_error("[%s] bad %s, wrong number of SOAs (%u)", adapter_str, is_axfr?"axfr":"ixfr", soa_seen); result = ODS_STATUS_ERR; } } /* input zone ok, set inbound serial and apply differences */ if (result == ODS_STATUS_OK || result == ODS_STATUS_UNCHANGED) { adapi_set_serial(zone, new_serial); if (is_axfr) { adapi_trans_full(zone); } else { adapi_trans_diff(zone); } if (result == ODS_STATUS_UNCHANGED) { result = ODS_STATUS_OK; } } return result; }