static int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, int is_axfr) { domain_type* domain; rrset_type* rrset; rdata_atom_type *rdatas; rr_type *rrs_old; ssize_t rdata_num; int rrnum; domain = domain_table_find(db->domains, dname); if(!domain) { /* create the domain */ domain = domain_table_insert(db->domains, dname); } rrset = domain_find_rrset(domain, zone, type); if(!rrset) { /* create the rrset */ rrset = region_alloc(db->region, sizeof(rrset_type)); if(!rrset) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } rrset->zone = zone; rrset->rrs = 0; rrset->rr_count = 0; domain_add_rrset(domain, rrset); } /* dnames in rdata are normalized, conform RFC 4035, * Section 6.2 */ rdata_num = rdata_wireformat_to_rdata_atoms( db->region, db->domains, type, rdatalen, packet, &rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "diff: bad rdata for %s", dname_to_string(dname,0)); return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num); if(rrnum != -1) { DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists", dname_to_string(dname,0), rrtype_to_string(type))); /* ignore already existing RR: lenient accepting of messages */ return 1; } /* re-alloc the rrs and add the new */ rrs_old = rrset->rrs; rrset->rrs = region_alloc(db->region, (rrset->rr_count+1) * sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } if(rrs_old) memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type)); region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count); rrset->rr_count ++; rrset->rrs[rrset->rr_count - 1].owner = domain; rrset->rrs[rrset->rr_count - 1].rdatas = rdatas; rrset->rrs[rrset->rr_count - 1].ttl = ttl; rrset->rrs[rrset->rr_count - 1].type = type; rrset->rrs[rrset->rr_count - 1].klass = klass; rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num; /* see if it is a SOA */ if(domain == zone->apex) { if(type == TYPE_SOA) { uint32_t soa_minimum; zone->soa_rrset = rrset; zone->updated = 1; /* BUG #103 tweaked SOA ttl value */ if(zone->soa_nx_rrset == 0) { zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); if(!zone->soa_nx_rrset) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } zone->soa_nx_rrset->rr_count = 1; zone->soa_nx_rrset->next = 0; zone->soa_nx_rrset->zone = zone; zone->soa_nx_rrset->rrs = region_alloc(db->region, sizeof(rr_type)); if(!zone->soa_nx_rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } } memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), rdata_atom_size(rrset->rrs->rdatas[6])); if (rrset->rrs->ttl > ntohl(soa_minimum)) { rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); } domain->has_SOA = 1; } if(type == TYPE_NS) { zone->ns_rrset = rrset; } if(type == TYPE_RRSIG) { int i; for (i = 0; i < rrset->rr_count; ++i) { if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) { zone->is_secure = 1; break; } } } } #ifdef NSEC3 #ifndef FULL_PREHASH if ((type == TYPE_NSEC3) && (rrset->rr_count == 1)) { /* NSEC3 RRset just added */ if (0 != namedb_add_nsec3_domain(db, domain, zone)) return 0; } if (is_axfr == 0) { struct domain *parent = domain; do { if (0 != namedb_add_nsec3_mod_domain(db, parent)) return 0; parent = parent->parent; } while (parent != zone->apex->parent); } #else (void)is_axfr; #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ return 1; }
static rrset_type * read_rrset(namedb_type *db, uint32_t domain_count, domain_type **domains, uint32_t zone_count, zone_type **zones) { rrset_type *rrset; int i, j; domain_type *owner; uint16_t type; uint16_t klass; uint32_t soa_minimum; owner = read_domain(db, domain_count, domains); if (!owner) return NULL; rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type)); rrset->zone = read_zone(db, zone_count, zones); if (!rrset->zone) return NULL; if (fread(&type, sizeof(type), 1, db->fd) != 1) return NULL; type = ntohs(type); if (fread(&klass, sizeof(klass), 1, db->fd) != 1) return NULL; klass = ntohs(klass); if (fread(&rrset->rr_count, sizeof(rrset->rr_count), 1, db->fd) != 1) return NULL; rrset->rr_count = ntohs(rrset->rr_count); rrset->rrs = (rr_type *) region_alloc( db->region, rrset->rr_count * sizeof(rr_type)); assert(rrset->rr_count > 0); for (i = 0; i < rrset->rr_count; ++i) { rr_type *rr = &rrset->rrs[i]; rr->owner = owner; rr->type = type; rr->klass = klass; if (fread(&rr->rdata_count, sizeof(rr->rdata_count), 1, db->fd) != 1) return NULL; rr->rdata_count = ntohs(rr->rdata_count); rr->rdatas = (rdata_atom_type *) region_alloc( db->region, rr->rdata_count * sizeof(rdata_atom_type)); if (fread(&rr->ttl, sizeof(rr->ttl), 1, db->fd) != 1) return NULL; rr->ttl = ntohl(rr->ttl); for (j = 0; j < rr->rdata_count; ++j) { if (!read_rdata_atom(db, rr->type, j, domain_count, domains, &rr->rdatas[j])) return NULL; } } domain_add_rrset(owner, rrset); if (rrset_rrtype(rrset) == TYPE_SOA) { assert(owner == rrset->zone->apex); rrset->zone->soa_rrset = rrset; /* BUG #103 add another soa with a tweaked ttl */ rrset->zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); rrset->zone->soa_nx_rrset->rrs = region_alloc(db->region, rrset->rr_count * sizeof(rr_type)); memcpy(rrset->zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); rrset->zone->soa_nx_rrset->rr_count = 1; rrset->zone->soa_nx_rrset->next = 0; /* also add a link to the zone */ rrset->zone->soa_nx_rrset->zone = rrset->zone; /* check the ttl and MINIMUM value and set accordinly */ memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), rdata_atom_size(rrset->rrs->rdatas[6])); if (rrset->rrs->ttl > ntohl(soa_minimum)) { rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); } owner->has_SOA = 1; } else if (owner == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_NS) { rrset->zone->ns_rrset = rrset; } #ifdef NSEC3 #ifndef FULL_PREHASH else if (type == TYPE_NSEC3) { if (0 != namedb_add_nsec3_domain(db, owner, rrset->zone)) { return NULL; } } #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ if (rrset_rrtype(rrset) == TYPE_RRSIG && owner == rrset->zone->apex) { for (i = 0; i < rrset->rr_count; ++i) { if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) { rrset->zone->is_secure = 1; break; } } } return rrset; }
int process_rr(void) { zone_type *zone = parser->current_zone; rr_type *rr = &parser->current_rr; rrset_type *rrset; size_t max_rdlength; int i; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rr->type); /* We only support IN class */ if (rr->klass != CLASS_IN) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("only class IN is supported"); else zc_error_prev_line("only class IN is supported"); return 0; } /* Make sure the maximum RDLENGTH does not exceed 65535 bytes. */ max_rdlength = rdata_maximum_wireformat_size( descriptor, rr->rdata_count, rr->rdatas); if (max_rdlength > MAX_RDLENGTH) { zc_error_prev_line("maximum rdata length exceeds %d octets", MAX_RDLENGTH); return 0; } /* we have the zone already */ assert(zone); if (rr->type == TYPE_SOA) { if (rr->owner != zone->apex) { zc_error_prev_line( "SOA record with invalid domain name"); return 0; } if(has_soa(rr->owner)) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("this SOA record was already encountered"); else zc_error_prev_line("this SOA record was already encountered"); return 0; } rr->owner->is_apex = 1; } if (!domain_is_subdomain(rr->owner, zone->apex)) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("out of zone data"); else zc_error_prev_line("out of zone data"); return 0; } /* Do we have this type of rrset already? */ rrset = domain_find_rrset(rr->owner, zone, rr->type); if (!rrset) { rrset = (rrset_type *) region_alloc(parser->region, sizeof(rrset_type)); rrset->zone = zone; rrset->rr_count = 1; rrset->rrs = (rr_type *) region_alloc(parser->region, sizeof(rr_type)); rrset->rrs[0] = *rr; /* Add it */ domain_add_rrset(rr->owner, rrset); } else { rr_type* o; if (rr->type != TYPE_RRSIG && rrset->rrs[0].ttl != rr->ttl) { zc_warning_prev_line( "%s TTL %u does not match the TTL %u of the %s RRset", domain_to_string(rr->owner), (unsigned)rr->ttl, (unsigned)rrset->rrs[0].ttl, rrtype_to_string(rr->type)); } /* Search for possible duplicates... */ for (i = 0; i < rrset->rr_count; i++) { if (!zrdatacmp(rr->type, rr, &rrset->rrs[i])) { break; } } /* Discard the duplicates... */ if (i < rrset->rr_count) { return 0; } if(rrset->rr_count == 65535) { zc_error_prev_line("too many RRs for domain RRset"); return 0; } /* Add it... */ o = rrset->rrs; rrset->rrs = (rr_type *) region_alloc_array(parser->region, (rrset->rr_count + 1), sizeof(rr_type)); memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type)); region_recycle(parser->region, o, (rrset->rr_count) * sizeof(rr_type)); rrset->rrs[rrset->rr_count] = *rr; ++rrset->rr_count; } if(rr->type == TYPE_DNAME && rrset->rr_count > 1) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("multiple DNAMEs at the same name"); else zc_error_prev_line("multiple DNAMEs at the same name"); } if(rr->type == TYPE_CNAME && rrset->rr_count > 1) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("multiple CNAMEs at the same name"); else zc_error_prev_line("multiple CNAMEs at the same name"); } if((rr->type == TYPE_DNAME && domain_find_rrset(rr->owner, zone, TYPE_CNAME)) ||(rr->type == TYPE_CNAME && domain_find_rrset(rr->owner, zone, TYPE_DNAME))) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("DNAME and CNAME at the same name"); else zc_error_prev_line("DNAME and CNAME at the same name"); } if(domain_find_rrset(rr->owner, zone, TYPE_CNAME) && domain_find_non_cname_rrset(rr->owner, zone)) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("CNAME and other data at the same name"); else zc_error_prev_line("CNAME and other data at the same name"); } /* Check we have SOA */ if(rr->owner == zone->apex) apex_rrset_checks(parser->db, rrset, rr->owner); if(parser->line % ZONEC_PCT_COUNT == 0 && time(NULL) > startzonec + ZONEC_PCT_TIME) { struct stat buf; startzonec = time(NULL); buf.st_size = 0; fstat(fileno(yyin), &buf); if(buf.st_size == 0) buf.st_size = 1; VERBOSITY(1, (LOG_INFO, "parse %s %d %%", parser->current_zone->opts->name, (int)((uint64_t)ftell(yyin)*(uint64_t)100/(uint64_t)buf.st_size))); } ++totalrrs; return 1; }
/** * Add RR. * */ ods_status zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats) { domain_type* domain = NULL; rrset_type* rrset = NULL; rr_type* record = NULL; ods_status status = ODS_STATUS_OK; ods_log_assert(rr); ods_log_assert(zone); ods_log_assert(zone->name); ods_log_assert(zone->db); ods_log_assert(zone->signconf); /* If we already have this RR, return ODS_STATUS_UNCHANGED */ domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr)); if (!domain) { domain = namedb_add_domain(zone->db, ldns_rr_owner(rr)); if (!domain) { ods_log_error("[%s] unable to add RR to zone %s: " "failed to add domain", zone_str, zone->name); return ODS_STATUS_ERR; } if (ldns_dname_compare(domain->dname, zone->apex) == 0) { domain->is_apex = 1; } else { status = namedb_domain_entize(zone->db, domain, zone->apex); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to add RR to zone %s: " "failed to entize domain", zone_str, zone->name); return ODS_STATUS_ERR; } } } rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr)); if (!rrset) { rrset = rrset_create(domain->zone, ldns_rr_get_type(rr)); if (!rrset) { ods_log_error("[%s] unable to add RR to zone %s: " "failed to add RRset", zone_str, zone->name); return ODS_STATUS_ERR; } domain_add_rrset(domain, rrset); } record = rrset_lookup_rr(rrset, rr); if (record) { record->is_added = 1; /* already exists, just mark added */ record->is_removed = 0; /* unset is_removed */ if (ldns_rr_ttl(rr) != ldns_rr_ttl(record->rr)) { ldns_rr_set_ttl(record->rr, ldns_rr_ttl(rr)); rrset->needs_signing = 1; } return ODS_STATUS_UNCHANGED; } else { record = rrset_add_rr(rrset, rr); ods_log_assert(record); ods_log_assert(record->rr); ods_log_assert(record->is_added); } /* update stats */ if (do_stats && zone->stats) { zone->stats->sort_count += 1; } return ODS_STATUS_OK; }