int diff_read_file(namedb_type* db, nsd_options_t* opt, struct diff_log** log, size_t child_count) { const char* filename = opt->difffile; FILE *df; uint32_t type, timestamp[2], curr_timestamp[2]; struct diff_read_data* data = diff_read_data_create(); off_t startpos; df = fopen(filename, "r"); if(!df) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "could not open file %s for reading: %s", filename, strerror(errno))); region_destroy(data->region); return 1; } /* check timestamp */ curr_timestamp[0] = (uint32_t) db->diff_timestamp.tv_sec; curr_timestamp[1] = (uint32_t) db->diff_timestamp.tv_usec; if(!diff_read_32(df, &type)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "difffile %s is empty", filename)); db->diff_skip = 0; db->diff_pos = 0; } else if (!diff_read_32(df, ×tamp[0]) || !diff_read_32(df, ×tamp[1])) { log_msg(LOG_ERR, "difffile %s bad first part: no timestamp", filename); region_destroy(data->region); fclose(df); return 0; } else if (curr_timestamp[0] != timestamp[0] || curr_timestamp[1] != timestamp[1]) { /* new timestamp, no skipping */ db->diff_timestamp.tv_sec = (time_t) timestamp[0]; db->diff_timestamp.tv_usec = (suseconds_t) timestamp[1]; if (db->diff_skip) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "new timestamp on " "difffile %s, restoring diff_skip and diff_pos " "[old timestamp: %u.%u; new timestamp: %u.%u]", filename, curr_timestamp[0], curr_timestamp[1], timestamp[0], timestamp[1])); db->diff_skip = 0; db->diff_pos = 0; } } /* Always seek, to diff_pos or to beginning of the file. */ if (fseeko(df, 0, SEEK_SET)==-1) { log_msg(LOG_INFO, "could not fseeko file %s: %s.", filename, strerror(errno)); region_destroy(data->region); fclose(df); return 0; } if(db->diff_skip) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skip diff file")); if(fseeko(df, db->diff_pos, SEEK_SET)==-1) { log_msg(LOG_INFO, "could not fseeko file %s: %s. " "Reread from start.", filename, strerror(errno)); } } startpos = ftello(df); if(startpos == -1) { log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); region_destroy(data->region); fclose(df); return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "start of diff file read at pos %u", (uint32_t) db->diff_pos)); while(diff_read_32(df, &type)) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "iter loop")); /* read timestamp */ if(!diff_read_32(df, ×tamp[0]) || !diff_read_32(df, ×tamp[1])) { log_msg(LOG_INFO, "could not read timestamp: %s.", strerror(errno)); region_destroy(data->region); fclose(df); return 0; } if(!read_process_part(db, df, type, opt, data, log, child_count, &startpos)) { log_msg(LOG_INFO, "error processing diff file"); region_destroy(data->region); fclose(df); return 0; } startpos = ftello(df); if(startpos == -1) { log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); region_destroy(data->region); fclose(df); return 0; } } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "end of diff file read")); if(find_smallest_offset(data, &db->diff_pos)) { /* can skip to the first unused element */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file")); db->diff_skip = 1; } else { /* all processed, can skip to here next time */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file")); db->diff_skip = 1; db->diff_pos = ftello(df); if(db->diff_pos == -1) { log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); db->diff_skip = 0; } } region_destroy(data->region); fclose(df); return 1; }
/* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */ static int apply_ixfr(namedb_type* db, FILE *in, const off_t* startpos, const char* zone, uint32_t serialno, nsd_options_t* opt, uint16_t id, uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, size_t child_count) { uint32_t filelen, msglen, pkttype, timestamp[2]; int qcount, ancount, counter; buffer_type* packet; region_type* region; int i; uint16_t rrlen; const dname_type *dname_zone, *dname; zone_type* zone_db; domain_type* last_in_list; char file_zone_name[3072]; uint32_t file_serial, file_seq_nr; uint16_t file_id; off_t mempos; memmove(&mempos, startpos, sizeof(off_t)); if(fseeko(in, mempos, SEEK_SET) == -1) { log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno)); return 0; } /* read ixfr packet RRs and apply to in memory db */ if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_IXFR) { log_msg(LOG_ERR, "could not read type or wrong type"); return 0; } if(!diff_read_32(in, ×tamp[0]) || !diff_read_32(in, ×tamp[1])) { log_msg(LOG_ERR, "could not read timestamp"); return 0; } if(!diff_read_32(in, &filelen)) { log_msg(LOG_ERR, "could not read len"); return 0; } /* read header */ if(filelen < QHEADERSZ + sizeof(uint32_t)*3 + sizeof(uint16_t)) { log_msg(LOG_ERR, "msg too short"); return 0; } region = region_create(xalloc, free); if(!region) { log_msg(LOG_ERR, "out of memory"); return 0; } if(!diff_read_str(in, file_zone_name, sizeof(file_zone_name)) || !diff_read_32(in, &file_serial) || !diff_read_16(in, &file_id) || !diff_read_32(in, &file_seq_nr)) { log_msg(LOG_ERR, "could not part data"); region_destroy(region); return 0; } if(strcmp(file_zone_name, zone) != 0 || serialno != file_serial || id != file_id || seq_nr != file_seq_nr) { log_msg(LOG_ERR, "internal error: reading part with changed id"); region_destroy(region); return 0; } msglen = filelen - sizeof(uint32_t)*3 - sizeof(uint16_t) - strlen(file_zone_name); packet = buffer_create(region, QIOBUFSZ); dname_zone = dname_parse(region, zone); zone_db = find_zone(db, dname_zone, opt, child_count); if(!zone_db) { log_msg(LOG_ERR, "no zone exists"); region_destroy(region); /* break out and stop the IXFR, ignore it */ return 2; } if(msglen > QIOBUFSZ) { log_msg(LOG_ERR, "msg too long"); region_destroy(region); return 0; } buffer_clear(packet); if(fread(buffer_begin(packet), msglen, 1, in) != 1) { log_msg(LOG_ERR, "short fread: %s", strerror(errno)); region_destroy(region); return 0; } buffer_set_limit(packet, msglen); /* only answer section is really used, question, additional and authority section RRs are skipped */ qcount = QDCOUNT(packet); ancount = ANCOUNT(packet); buffer_skip(packet, QHEADERSZ); /* skip queries */ for(i=0; i<qcount; ++i) if(!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "bad RR in question section"); region_destroy(region); return 0; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: started packet for zone %s", dname_to_string(dname_zone, 0))); /* first RR: check if SOA and correct zone & serialno */ if(*rr_count == 0) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parse first RR", dname_to_string(dname_zone, 0))); dname = dname_make_from_packet(region, packet, 1, 1); if(!dname) { log_msg(LOG_ERR, "could not parse dname"); region_destroy(region); return 0; } if(dname_compare(dname_zone, dname) != 0) { log_msg(LOG_ERR, "SOA dname %s not equal to zone", dname_to_string(dname,0)); log_msg(LOG_ERR, "zone dname is %s", dname_to_string(dname_zone,0)); region_destroy(region); return 0; } if(!buffer_available(packet, 10)) { log_msg(LOG_ERR, "bad SOA RR"); region_destroy(region); return 0; } if(buffer_read_u16(packet) != TYPE_SOA || buffer_read_u16(packet) != CLASS_IN) { log_msg(LOG_ERR, "first RR not SOA IN"); region_destroy(region); return 0; } buffer_skip(packet, sizeof(uint32_t)); /* ttl */ if(!buffer_available(packet, buffer_read_u16(packet)) || !packet_skip_dname(packet) /* skip prim_ns */ || !packet_skip_dname(packet) /* skip email */) { log_msg(LOG_ERR, "bad SOA RR"); region_destroy(region); return 0; } if(buffer_read_u32(packet) != serialno) { buffer_skip(packet, -4); log_msg(LOG_ERR, "SOA serial %d different from commit %d", buffer_read_u32(packet), serialno); region_destroy(region); return 0; } buffer_skip(packet, sizeof(uint32_t)*4); counter = 1; *rr_count = 1; *is_axfr = 0; *delete_mode = 0; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } else counter = 0; last_in_list = zone_db->apex; for(; counter < ancount; ++counter,++(*rr_count)) { uint16_t type, klass; uint32_t ttl; if(!(dname=dname_make_from_packet(region, packet, 1,1))) { log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count); region_destroy(region); return 0; } if(!buffer_available(packet, 10)) { log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count); region_destroy(region); return 0; } type = buffer_read_u16(packet); klass = buffer_read_u16(packet); ttl = buffer_read_u32(packet); rrlen = buffer_read_u16(packet); if(!buffer_available(packet, rrlen)) { log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d", *rr_count, rrlen, (int)buffer_remaining(packet)); region_destroy(region); return 0; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); if(*rr_count == 1 && type != TYPE_SOA) { /* second RR: if not SOA: this is an AXFR; delete all zone contents */ delete_zone_rrs(db, zone_db); /* add everything else (incl end SOA) */ *delete_mode = 0; *is_axfr = 1; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } if(*rr_count == 1 && type == TYPE_SOA) { /* if the serial no of the SOA equals the serialno, then AXFR */ size_t bufpos = buffer_position(packet); uint32_t thisserial; if(!packet_skip_dname(packet) || !packet_skip_dname(packet) || buffer_remaining(packet) < sizeof(uint32_t)*5) { log_msg(LOG_ERR, "bad xfr SOA RR formerr."); region_destroy(region); return 0; } thisserial = buffer_read_u32(packet); if(thisserial == serialno) { /* AXFR */ delete_zone_rrs(db, zone_db); *delete_mode = 0; *is_axfr = 1; } /* must have stuff in memory for a successful IXFR, * the serial number of the SOA has been checked * previously (by check_for_bad_serial) if it exists */ if(!*is_axfr && !domain_find_rrset(zone_db->apex, zone_db, TYPE_SOA)) { log_msg(LOG_ERR, "%s SOA serial %d is not " "in memory, skip IXFR", zone, serialno); region_destroy(region); /* break out and stop the IXFR, ignore it */ return 2; } buffer_set_position(packet, bufpos); } if(type == TYPE_SOA && !*is_axfr) { /* switch from delete-part to add-part and back again, just before soa - so it gets deleted and added too */ /* this means we switch to delete mode for the final SOA */ *delete_mode = !*delete_mode; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } if(type == TYPE_TSIG || type == TYPE_OPT) { /* ignore pseudo RRs */ buffer_skip(packet, rrlen); continue; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s", *delete_mode?"del":"add", dname_to_string(dname,0), rrtype_to_string(type))); if(*delete_mode) { /* delete this rr */ if(!*is_axfr && type == TYPE_SOA && counter==ancount-1 && seq_nr == seq_total-1) { continue; /* do not delete final SOA RR for IXFR */ } if(!delete_RR(db, dname, type, klass, last_in_list, packet, rrlen, zone_db, region, *is_axfr)) { region_destroy(region); return 0; } if (!*is_axfr && last_in_list->nextdiff) { last_in_list = last_in_list->nextdiff; } } else { /* add this rr */ if(!add_RR(db, dname, type, klass, ttl, packet, rrlen, zone_db, *is_axfr)) { region_destroy(region); return 0; } } } fix_empty_terminals(zone_db); region_destroy(region); return 1; }
static int read_sure_part(namedb_type* db, FILE *in, nsd_options_t* opt, struct diff_read_data* data, struct diff_log** log, size_t child_count) { char zone_buf[3072]; char log_buf[5120]; uint32_t old_serial, new_serial, num_parts; uint16_t id; uint8_t committed; struct diff_zone *zp; uint32_t i; int have_all_parts = 1; struct diff_log* thislog = 0; off_t commitpos; /* read zone name and serial */ if(!diff_read_str(in, zone_buf, sizeof(zone_buf)) || !diff_read_32(in, &old_serial) || !diff_read_32(in, &new_serial) || !diff_read_16(in, &id) || !diff_read_32(in, &num_parts)) { log_msg(LOG_ERR, "diff file bad commit part"); return 0; } commitpos = ftello(in); /* position of commit byte */ if(commitpos == -1) { log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); return 0; } if(!diff_read_8(in, &committed) || !diff_read_str(in, log_buf, sizeof(log_buf)) ) { log_msg(LOG_ERR, "diff file bad commit part"); return 0; } if(log) { thislog = (struct diff_log*)region_alloc(db->region, sizeof(struct diff_log)); if(!thislog) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } thislog->zone_name = region_strdup(db->region, zone_buf); thislog->comment = region_strdup(db->region, log_buf); thislog->error = 0; thislog->next = *log; *log = thislog; } /* has been read in completely */ zp = diff_read_find_zone(data, zone_buf); if(!zp) { log_msg(LOG_ERR, "diff file commit without IXFR"); if(thislog) thislog->error = "error no IXFR parts"; return 1; } if(committed && check_for_bad_serial(db, zone_buf, old_serial)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "skipping diff file commit with bad serial")); zp->parts->root = RBTREE_NULL; zp->parts->count = 0; if(thislog) thislog->error = "error bad serial"; return 1; } for(i=0; i<num_parts; i++) { struct diff_xfrpart *xp = diff_read_find_part(zp, i); if(!xp || xp->id != id || xp->new_serial != new_serial) { have_all_parts = 0; } } if(!have_all_parts) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "skipping diff file commit without all parts")); if(thislog) thislog->error = "error missing parts"; } if(committed && have_all_parts) { int is_axfr=0, delete_mode=0, rr_count=0; off_t resume_pos; #ifdef NSEC3 #ifndef FULL_PREHASH struct region *region; dname_type const *zone_dname; struct zone *zone; region = region_create(xalloc, free); if (region == NULL) { log_msg(LOG_ERR, "out of memory"); return 0; } zone_dname = dname_parse(region, zone_buf); if (zone_dname == NULL) { log_msg(LOG_ERR, "out of memory"); region_destroy(region); return 0; } zone = find_zone(db, zone_dname, opt, child_count); region_destroy(region); if (zone == NULL) { log_msg(LOG_ERR, "no zone exists"); /* just stop trying applying ixfr */ return 1; } if (0 != namedb_nsec3_mod_domains_create(db)) { log_msg(LOG_ERR, "unable to allocate space " "for modified NSEC3 domains"); return 0; } #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", log_buf)); resume_pos = ftello(in); if(resume_pos == -1) { log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); return 0; } for(i=0; i<num_parts; i++) { struct diff_xfrpart *xp = diff_read_find_part(zp, i); int ret; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i)); ret = apply_ixfr(db, in, &xp->file_pos, zone_buf, new_serial, opt, id, xp->seq_nr, num_parts, &is_axfr, &delete_mode, &rr_count, child_count); if(ret == 0) { log_msg(LOG_ERR, "bad ixfr packet part %d in %s", (int)i, opt->difffile); mark_and_exit(opt, in, commitpos, log_buf); } else if(ret == 2) { break; } } #ifdef NSEC3 #ifndef FULL_PREHASH if (is_axfr != 0) prehash_zone(db, zone); else prehash_zone_incremental(db, zone); #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ if(fseeko(in, resume_pos, SEEK_SET) == -1) { log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno)); return 0; } } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", log_buf)); } /* clean out the parts for the zone after the commit/rollback */ zp->parts->root = RBTREE_NULL; zp->parts->count = 0; return 1; }
void nsd_options_destroy(nsd_options_t* opt) { region_destroy(opt->region); }
ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t data_size, buffer_type *packet, rdata_atom_type **rdatas) { size_t end = buffer_position(packet) + data_size; size_t i; rdata_atom_type temp_rdatas[MAXRDATALEN]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); region_type *temp_region; assert(descriptor->maximum <= MAXRDATALEN); if (!buffer_available(packet, data_size)) { return -1; } temp_region = region_create(xalloc, free); for (i = 0; i < descriptor->maximum; ++i) { int is_domain = 0; int is_normalized = 0; int is_wirestore = 0; size_t length = 0; int required = i < descriptor->minimum; switch (rdata_atom_wireformat_type(rrtype, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: is_domain = 1; is_normalized = 1; break; case RDATA_WF_LITERAL_DNAME: is_domain = 1; is_wirestore = 1; break; case RDATA_WF_BYTE: length = sizeof(uint8_t); break; case RDATA_WF_SHORT: length = sizeof(uint16_t); break; case RDATA_WF_LONG: length = sizeof(uint32_t); break; case RDATA_WF_TEXTS: case RDATA_WF_LONG_TEXT: length = end - buffer_position(packet); break; case RDATA_WF_TEXT: case RDATA_WF_BINARYWITHLENGTH: /* Length is stored in the first byte. */ length = 1; if (buffer_position(packet) + length <= end) { length += buffer_current(packet)[length - 1]; } break; case RDATA_WF_A: length = sizeof(in_addr_t); break; case RDATA_WF_AAAA: length = IP6ADDRLEN; break; case RDATA_WF_ILNP64: length = IP6ADDRLEN/2; break; case RDATA_WF_EUI48: length = EUI48ADDRLEN; break; case RDATA_WF_EUI64: length = EUI64ADDRLEN; break; case RDATA_WF_BINARY: /* Remaining RDATA is binary. */ length = end - buffer_position(packet); break; case RDATA_WF_APL: length = (sizeof(uint16_t) /* address family */ + sizeof(uint8_t) /* prefix */ + sizeof(uint8_t)); /* length */ if (buffer_position(packet) + length <= end) { /* Mask out negation bit. */ length += (buffer_current(packet)[length - 1] & APL_LENGTH_MASK); } break; case RDATA_WF_IPSECGATEWAY: switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ { default: case IPSECKEY_NOGATEWAY: length = 0; break; case IPSECKEY_IP4: length = IP4ADDRLEN; break; case IPSECKEY_IP6: length = IP6ADDRLEN; break; case IPSECKEY_DNAME: is_domain = 1; is_normalized = 1; is_wirestore = 1; break; } break; } if (is_domain) { const dname_type *dname; if (!required && buffer_position(packet) == end) { break; } dname = dname_make_from_packet( temp_region, packet, 1, is_normalized); if (!dname || buffer_position(packet) > end) { /* Error in domain name. */ region_destroy(temp_region); return -1; } if(is_wirestore) { temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + dname->name_size); temp_rdatas[i].data[0] = dname->name_size; memcpy(temp_rdatas[i].data+1, dname_name(dname), dname->name_size); } else { temp_rdatas[i].domain = domain_table_insert(owners, dname); temp_rdatas[i].domain->usage ++; } } else { if (buffer_position(packet) + length > end) { if (required) { /* Truncated RDATA. */ region_destroy(temp_region); return -1; } else { break; } } if (!required && buffer_position(packet) == end) { break; } temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + length); temp_rdatas[i].data[0] = length; buffer_read(packet, temp_rdatas[i].data + 1, length); } } if (buffer_position(packet) < end) { /* Trailing garbage. */ region_destroy(temp_region); return -1; } *rdatas = (rdata_atom_type *) region_alloc_init( region, temp_rdatas, i * sizeof(rdata_atom_type)); region_destroy(temp_region); return (ssize_t)i; }
struct namedb * namedb_open (const char *filename, nsd_options_t* opt, size_t num_children) { namedb_type *db; /* * Temporary region used while loading domain names from the * database. The region is freed after each time a dname is * read from the database. */ region_type *dname_region; /* * Temporary region used to store array of domains and zones * while loading the database. The region is freed before * returning. */ region_type *temp_region; uint32_t dname_count; domain_type **domains; /* Indexed by domain number. */ uint32_t zone_count; zone_type **zones; /* Indexed by zone number. */ uint32_t i; uint32_t rrset_count = 0; uint32_t rr_count = 0; rrset_type *rrset; DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(namedb_type) = %lu\n", (unsigned long) sizeof(namedb_type))); DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(zone_type) = %lu\n", (unsigned long) sizeof(zone_type))); DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(domain_type) = %lu\n", (unsigned long) sizeof(domain_type))); DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(rrset_type) = %lu\n", (unsigned long) sizeof(rrset_type))); DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(rr_type) = %lu\n", (unsigned long) sizeof(rr_type))); DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(rdata_atom_type) = %lu\n", (unsigned long) sizeof(rdata_atom_type))); DEBUG(DEBUG_DBACCESS, 2, (LOG_INFO, "sizeof(rbnode_t) = %lu\n", (unsigned long) sizeof(rbnode_t))); if ((db = namedb_create()) == NULL) { log_msg(LOG_ERR, "insufficient memory to create database"); return NULL; } db->filename = region_strdup(db->region, filename); if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { log_msg(LOG_ERR, "unable to load %s: cannot initialize" "timestamp", db->filename); namedb_destroy(db); return NULL; } /* Open it... */ db->fd = fopen(db->filename, "r"); if (db->fd == NULL) { log_msg(LOG_ERR, "unable to load %s: %s", db->filename, strerror(errno)); namedb_destroy(db); return NULL; } if (!read_magic(db)) { log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename); log_msg(LOG_ERR, "cannot load database, incompatible version " "number. Please rebuild database and " "start again."); namedb_close(db); return NULL; } if (!read_size(db, &zone_count)) { log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename); namedb_close(db); return NULL; } DEBUG(DEBUG_DBACCESS, 1, (LOG_INFO, "Retrieving %lu zones\n", (unsigned long) zone_count)); temp_region = region_create(xalloc, free); dname_region = region_create(xalloc, free); db->zone_count = zone_count; zones = (zone_type **) region_alloc(temp_region, zone_count * sizeof(zone_type *)); for (i = 0; i < zone_count; ++i) { const dname_type *dname = read_dname(db->fd, dname_region); if (!dname) { log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename); region_destroy(dname_region); region_destroy(temp_region); namedb_close(db); return NULL; } zones[i] = (zone_type *) region_alloc(db->region, sizeof(zone_type)); zones[i]->next = db->zones; db->zones = zones[i]; zones[i]->apex = domain_table_insert(db->domains, dname); zones[i]->soa_rrset = NULL; zones[i]->soa_nx_rrset = NULL; zones[i]->ns_rrset = NULL; #ifdef NSEC3 zones[i]->nsec3_soa_rr = NULL; zones[i]->nsec3_last = NULL; #endif zones[i]->opts = zone_options_find(opt, domain_dname(zones[i]->apex)); zones[i]->number = i + 1; zones[i]->is_secure = 0; zones[i]->updated = 1; zones[i]->is_ok = 0; zones[i]->dirty = region_alloc(db->region, sizeof(uint8_t)*num_children); memset(zones[i]->dirty, 0, sizeof(uint8_t)*num_children); if(!zones[i]->opts) { log_msg(LOG_ERR, "cannot load database. Zone %s in db " "%s, but not in config file (might " "happen if you edited the config " "file). Please rebuild database and " "start again.", dname_to_string(dname, NULL), db->filename); region_destroy(dname_region); region_destroy(temp_region); namedb_close(db); return NULL; } #ifdef NSEC3 #ifndef FULL_PREHASH zones[i]->nsec3_domains = NULL; if (0 != zone_nsec3_domains_create(db, zones[i])) { log_msg(LOG_ERR, "insufficient memory for NSEC3 tree, " "unable to read database"); region_destroy(dname_region); region_destroy(temp_region); namedb_close(db); return NULL; } #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ region_free_all(dname_region); } if (!read_size(db, &dname_count)) { log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename); region_destroy(dname_region); region_destroy(temp_region); namedb_close(db); return NULL; } DEBUG(DEBUG_DBACCESS, 1, (LOG_INFO, "Retrieving %lu domain names\n", (unsigned long) dname_count)); domains = (domain_type **) region_alloc( temp_region, dname_count * sizeof(domain_type *)); for (i = 0; i < dname_count; ++i) { const dname_type *dname = read_dname(db->fd, dname_region); if (!dname) { log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename); region_destroy(dname_region); region_destroy(temp_region); namedb_close(db); return NULL; } domains[i] = domain_table_insert(db->domains, dname); region_free_all(dname_region); } region_destroy(dname_region); #ifndef NDEBUG fprintf(stderr, "database region after loading domain names: "); region_dump_stats(db->region, stderr); fprintf(stderr, "\n"); #endif while ((rrset = read_rrset(db, dname_count, domains, zone_count, zones))) { ++rrset_count; rr_count += rrset->rr_count; } DEBUG(DEBUG_DBACCESS, 1, (LOG_INFO, "Retrieved %lu RRs in %lu RRsets\n", (unsigned long) rr_count, (unsigned long) rrset_count)); region_destroy(temp_region); if ((db->crc_pos = ftello(db->fd)) == -1) { log_msg(LOG_ERR, "ftello %s failed: %s", db->filename, strerror(errno)); namedb_close(db); return NULL; } if (!read_size(db, &db->crc)) { log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename); namedb_close(db); return NULL; } if (!read_magic(db)) { log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename); log_msg(LOG_ERR, "cannot load database, incompatible version " "number. Please rebuild database and " "start again."); namedb_close(db); return NULL; } fclose(db->fd); db->fd = NULL; #ifndef NDEBUG fprintf(stderr, "database region after loading database: "); region_dump_stats(db->region, stderr); fprintf(stderr, "\n"); #endif return db; }
/* * Flash map is a string like "2x16K/l,6x16K,63x128K", where "2x16K" * means "two blocks of size 16 Kbytes each", and the "/l" is a flag * meaning "locked" (used for boot blocks which can't be programmed * without special intervention). Possible size suffixes are none * (bytes), "K" (kilobytes), and "M" (megabytes). Parse with a little * state machine, and add the blocks as a mem_region_t chain that's a * child of the given one. */ int flash_parse_map(mem_region_t *mr, const char *map) { enum state { S_NBLOCKS, S_SIZE, S_FLAGS, S_END } state = S_NBLOCKS; mem_region_t *cur = mr; int nblocks = 0; tsize_t size = 0; taddr_t vma, lma; unsigned flags = 0; const char *p; assert(mr); vma = mr->vma; lma = mr->lma; assert(map); /* clear out prior flash blocks */ region_destroy(mr->children); mr->children = NULL; p = map; goto loop; do { ++p; loop: if (isspace(*p)) continue; switch (state) { case S_NBLOCKS: if (isdigit(*p)) { nblocks = (nblocks * 10) + (*p - '0'); } else if (*p == 'x') { state = S_SIZE; } else { bad_map(map, p); goto failure; } break; case S_SIZE: switch (*p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': size = (size * 10) + (*p - '0'); break; case 'K': size *= 1024; break; case 'M': size *= (1024 * 1024); break; case '/': state = S_FLAGS; break; case ',': case '\0': state = S_END; break; default: bad_map(map, p); goto failure; } break; case S_FLAGS: switch (*p) { case 'l': flags |= MRF_LOCKED; break; case ',': case '\0': state = S_END; break; default: bad_map(map, p); goto failure; } break; default: assert(0); } if (state == S_END) { /* * Create one mem_region_t for each flash * block, and link them into a chain. */ while (nblocks--) { mem_region_t *tmp = region_new(); tmp->name = xstrdup("(anonymous flash block)"); tmp->type = MEMTYPE_FLASH; tmp->size = size; tmp->flags = flags; tmp->bufsize = mr->bufsize; tmp->vma = vma; vma += size; tmp->lma = lma; lma += size; if (cur == mr) { mr->children = tmp; cur = tmp; } else { cur->next = tmp; cur = tmp; } } if(flags != 0) mr->flags |= flags; state = S_NBLOCKS; nblocks = 0; size = 0; flags = 0; } } while (*p); return 0; failure: region_destroy(mr->children); mr->children = NULL; return -1; }