/** add tsig_key contents */ void key_options_setup(region_type* region, key_options_t* key) { uint8_t data[16384]; /* 16KB */ int size; if(!key->tsig_key) { /* create it */ key->tsig_key = (tsig_key_type *) region_alloc(region, sizeof(tsig_key_type)); /* create name */ key->tsig_key->name = dname_parse(region, key->name); if(!key->tsig_key->name) { log_msg(LOG_ERR, "Failed to parse tsig key name %s", key->name); /* key and base64 were checked during syntax parse */ exit(1); } key->tsig_key->size = 0; key->tsig_key->data = NULL; } size = b64_pton(key->secret, data, sizeof(data)); if(size == -1) { log_msg(LOG_ERR, "Failed to parse tsig key data %s", key->name); /* key and base64 were checked during syntax parse */ exit(1); } key->tsig_key->size = size; key->tsig_key->data = (uint8_t *)region_alloc_init(region, data, size); }
void key_options_tsig_add(nsd_options_t* opt) { key_options_t* optkey; uint8_t data[4000]; tsig_key_type* tsigkey; const dname_type* dname; int size; for(optkey = opt->keys; optkey; optkey = optkey->next) { dname = dname_parse(opt->region, optkey->name); if(!dname) { log_msg(LOG_ERR, "Failed to parse tsig key name %s", optkey->name); continue; } size = b64_pton(optkey->secret, data, sizeof(data)); if(size == -1) { log_msg(LOG_ERR, "Failed to parse tsig key data %s", optkey->name); continue; } tsigkey = (tsig_key_type *) region_alloc(opt->region, sizeof(tsig_key_type)); tsigkey->name = dname; tsigkey->size = size; tsigkey->data = (uint8_t *) region_alloc_init(opt->region, data, tsigkey->size); tsig_add_key(tsigkey); optkey->tsig_key = tsigkey; } }
static struct diff_zone* diff_read_find_zone(struct diff_read_data* data, const char* name) { const dname_type* dname = dname_parse(data->region, name); struct diff_zone* zp = (struct diff_zone*) rbtree_search(data->zones, dname); return zp; }
void config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o, const char *z) { zone_options_t* zone; ip_address_option_t* ip; if (k) { /* find key */ key_options_t* key = opt->keys; for( ; key ; key=key->next) { if(strcmp(key->name, k) == 0) { if (s) { quote(key->secret); } else { quote(key->algorithm); } return; } } printf("Could not find key %s\n", k); return; } if (!o) { return; } if (z) { const dname_type *dname = dname_parse(opt->region, z); if(!dname) { printf("Could not parse zone name %s\n", z); exit(1); } /* look per zone */ RBTREE_FOR(zone, zone_options_t*, opt->zone_options) { if (dname_compare(dname, zone->node.key) == 0) { /* -z matches, return are in the defines */ ZONE_GET_STR(name, o); ZONE_GET_STR(zonefile, o); ZONE_GET_ACL(request_xfr, o); ZONE_GET_ACL(provide_xfr, o); ZONE_GET_ACL(allow_notify, o); ZONE_GET_ACL(notify, o); ZONE_GET_BIN(notify_retry, o); ZONE_GET_OUTGOING(outgoing_interface, o); ZONE_GET_BIN(allow_axfr_fallback, o); printf("Zone option not handled: %s %s\n", z, o); exit(1); } } printf("Zone does not exist: %s\n", z); exit(1); } else {
int nsd_options_insert_zone(nsd_options_t* opt, zone_options_t* zone) { /* create dname for lookup */ const dname_type* dname = dname_parse(opt->region, zone->name); if(!dname) return 0; zone->node.key = dname; if(!rbtree_insert(opt->zone_options, (rbnode_t*)zone)) return 0; return 1; }
static struct diff_zone* diff_read_insert_zone(struct diff_read_data* data, const char* name) { const dname_type* dname = dname_parse(data->region, name); struct diff_zone* zp = region_alloc(data->region, sizeof(struct diff_zone)); if(!zp) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } zp->node = *RBTREE_NULL; zp->node.key = dname; zp->parts = rbtree_create(data->region, intcompf); rbtree_insert(data->zones, (rbnode_t*)zp); return zp; }
static int check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) { /* see if serial OK with in-memory serial */ domain_type* domain; region_type* region = region_create(xalloc, free); const dname_type* zone_name = dname_parse(region, zone_str); zone_type* zone = 0; domain = domain_table_find(db->domains, zone_name); if(domain) zone = domain_find_zone(domain); if(zone && zone->apex == domain && zone->soa_rrset && old_serial) { uint32_t memserial; memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); if(old_serial != ntohl(memserial)) { region_destroy(region); return 1; } } region_destroy(region); return 0; }
void xfrd_read_state(struct xfrd_state* xfrd) { const char* statefile = xfrd->nsd->options->xfrdfile; FILE *in; uint32_t filetime = 0; uint32_t numzones, i; region_type *tempregion; tempregion = region_create(xalloc, free); if(!tempregion) return; in = fopen(statefile, "r"); if(!in) { if(errno != ENOENT) { log_msg(LOG_ERR, "xfrd: Could not open file %s for reading: %s", statefile, strerror(errno)); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: no file %s. refreshing all zones.", statefile)); } region_destroy(tempregion); return; } if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC) || !xfrd_read_check_str(in, "filetime:") || !xfrd_read_i32(in, &filetime) || (time_t)filetime > xfrd_time()+15 || !xfrd_read_check_str(in, "numzones:") || !xfrd_read_i32(in, &numzones)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); fclose(in); region_destroy(tempregion); return; } for(i=0; i<numzones; i++) { char *p; xfrd_zone_t* zone; const dname_type* dname; uint32_t state, masnum, nextmas, round_num, timeout; xfrd_soa_t soa_nsd_read, soa_disk_read, soa_notified_read; time_t soa_nsd_acquired_read, soa_disk_acquired_read, soa_notified_acquired_read; xfrd_soa_t incoming_soa; time_t incoming_acquired; memset(&soa_nsd_read, 0, sizeof(soa_nsd_read)); memset(&soa_disk_read, 0, sizeof(soa_disk_read)); memset(&soa_notified_read, 0, sizeof(soa_notified_read)); if(!xfrd_read_check_str(in, "zone:") || !xfrd_read_check_str(in, "name:") || !(p=xfrd_read_token(in)) || !(dname = dname_parse(tempregion, p)) || !xfrd_read_check_str(in, "state:") || !xfrd_read_i32(in, &state) || (state>2) || !xfrd_read_check_str(in, "master:") || !xfrd_read_i32(in, &masnum) || !xfrd_read_check_str(in, "next_master:") || !xfrd_read_i32(in, &nextmas) || !xfrd_read_check_str(in, "round_num:") || !xfrd_read_i32(in, &round_num) || !xfrd_read_check_str(in, "next_timeout:") || !xfrd_read_i32(in, &timeout) || !xfrd_read_state_soa(in, "soa_nsd_acquired:", "soa_nsd:", &soa_nsd_read, &soa_nsd_acquired_read) || !xfrd_read_state_soa(in, "soa_disk_acquired:", "soa_disk:", &soa_disk_read, &soa_disk_acquired_read) || !xfrd_read_state_soa(in, "soa_notify_acquired:", "soa_notify:", &soa_notified_read, &soa_notified_acquired_read)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); fclose(in); region_destroy(tempregion); return; } zone = (xfrd_zone_t*)rbtree_search(xfrd->zones, dname); if(!zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: state file has info for not configured zone %s", p)); continue; } if(soa_nsd_acquired_read>xfrd_time()+15 || soa_disk_acquired_read>xfrd_time()+15 || soa_notified_acquired_read>xfrd_time()+15) { log_msg(LOG_ERR, "xfrd: statefile %s contains" " times in the future for zone %s. Ignoring.", statefile, zone->apex_str); continue; } zone->state = state; zone->master_num = masnum; zone->next_master = nextmas; zone->round_num = round_num; zone->timeout.tv_sec = timeout; zone->timeout.tv_usec = 0; /* read the zone OK, now set the master properly */ zone->master = acl_find_num(zone->zone_options->pattern-> request_xfr, zone->master_num); if(!zone->master) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: masters changed for zone %s", zone->apex_str)); zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; zone->round_num = 0; } /* * There is no timeout, * or there is a notification, * or there is a soa && current time is past refresh point */ if(timeout == 0 || soa_notified_acquired_read != 0 || (soa_disk_acquired_read != 0 && (uint32_t)xfrd_time() - soa_disk_acquired_read > ntohl(soa_disk_read.refresh))) { zone->state = xfrd_zone_refreshing; xfrd_set_refresh_now(zone); } /* There is a soa && current time is past expiry point */ if(soa_disk_acquired_read!=0 && (uint32_t)xfrd_time() - soa_disk_acquired_read > ntohl(soa_disk_read.expire)) { zone->state = xfrd_zone_expired; xfrd_set_refresh_now(zone); } /* handle as an incoming SOA. */ incoming_soa = zone->soa_nsd; incoming_acquired = zone->soa_nsd_acquired; zone->soa_nsd = soa_nsd_read; zone->soa_disk = soa_disk_read; zone->soa_notified = soa_notified_read; zone->soa_nsd_acquired = soa_nsd_acquired_read; /* we had better use what we got from starting NSD, not * what we store in this file, because the actual zone * contents trumps the contents of this cache */ /* zone->soa_disk_acquired = soa_disk_acquired_read; */ zone->soa_notified_acquired = soa_notified_acquired_read; xfrd_handle_incoming_soa(zone, &incoming_soa, incoming_acquired); } if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); region_destroy(tempregion); fclose(in); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: read %d zones from state file", (int)numzones)); fclose(in); region_destroy(tempregion); }
static void xfrd_init_zones() { zone_type *dbzone; zone_options_t *zone_opt; xfrd_zone_t *xzone; const dname_type* dname; assert(xfrd->zones == 0); assert(xfrd->nsd->db != 0); xfrd->zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); xfrd->notify_zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); RBTREE_FOR(zone_opt, zone_options_t*, xfrd->nsd->options->zone_options) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Zone %s\n", zone_opt->name)); dname = dname_parse(xfrd->region, zone_opt->name); if(!dname) { log_msg(LOG_ERR, "xfrd: Could not parse zone name %s.", zone_opt->name); continue; } dbzone = domain_find_zone(domain_table_find(xfrd->nsd->db->domains, dname)); if(dbzone && dname_compare(dname, domain_dname(dbzone->apex)) != 0) dbzone = 0; /* we found a parent zone */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: adding %s zone %s\n", dbzone?"filled":"empty", zone_opt->name)); init_notify_send(xfrd->notify_zones, xfrd->netio, xfrd->region, dname, zone_opt, dbzone); if(!zone_is_slave(zone_opt)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, master zone has no outgoing xfr requests", zone_opt->name)); continue; } xzone = (xfrd_zone_t*)region_alloc(xfrd->region, sizeof(xfrd_zone_t)); memset(xzone, 0, sizeof(xfrd_zone_t)); xzone->apex = dname; xzone->apex_str = zone_opt->name; xzone->state = xfrd_zone_refreshing; xzone->dirty = 0; xzone->zone_options = zone_opt; /* first retry will use first master */ xzone->master = 0; xzone->master_num = 0; xzone->next_master = 0; xzone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; xzone->soa_nsd_acquired = 0; xzone->soa_disk_acquired = 0; xzone->soa_notified_acquired = 0; /* [0]=1, [1]=0; "." domain name */ xzone->soa_nsd.prim_ns[0] = 1; xzone->soa_nsd.email[0] = 1; xzone->soa_disk.prim_ns[0]=1; xzone->soa_disk.email[0]=1; xzone->soa_notified.prim_ns[0]=1; xzone->soa_notified.email[0]=1; xzone->zone_handler.fd = -1; xzone->zone_handler.timeout = 0; xzone->zone_handler.user_data = xzone; xzone->zone_handler.event_types = NETIO_EVENT_READ|NETIO_EVENT_TIMEOUT; xzone->zone_handler.event_handler = xfrd_handle_zone; netio_add_handler(xfrd->netio, &xzone->zone_handler); xzone->tcp_conn = -1; xzone->tcp_waiting = 0; xzone->udp_waiting = 0; tsig_create_record_custom(&xzone->tsig, xfrd->region, 0, 0, 4); if(dbzone && dbzone->soa_rrset && dbzone->soa_rrset->rrs) { xzone->soa_nsd_acquired = xfrd_time(); xzone->soa_disk_acquired = xfrd_time(); /* we only use the first SOA in the rrset */ xfrd_copy_soa(&xzone->soa_nsd, dbzone->soa_rrset->rrs); xfrd_copy_soa(&xzone->soa_disk, dbzone->soa_rrset->rrs); } /* set refreshing anyway, we have data but it may be old */ xfrd_set_refresh_now(xzone); xzone->node.key = dname; rbtree_insert(xfrd->zones, (rbnode_t*)xzone); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: started server %d secondary zones", (int)xfrd->zones->count)); }
/* 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; }
/* * Reads the specified zone into the memory * nsd_options can be NULL if no config file is passed. */ unsigned int zonec_read(const char* name, const char* zonefile, zone_type* zone) { const dname_type *dname; totalrrs = 0; startzonec = time(NULL); parser->errors = 0; dname = dname_parse(parser->rr_region, name); if (!dname) { zc_error("incorrect zone name '%s'", name); return 1; } #ifndef ROOT_SERVER /* Is it a root zone? Are we a root server then? Idiot proof. */ if (dname->label_count == 1) { zc_error("not configured as a root server"); return 1; } #endif /* Open the zone file */ if (!zone_open(zonefile, 3600, CLASS_IN, dname)) { zc_error("cannot open '%s': %s", zonefile, strerror(errno)); return 1; } parser->current_zone = zone; /* Parse and process all RRs. */ yyparse(); /* remove origin if it was unused */ if(parser->origin != error_domain) domain_table_deldomain(parser->db, parser->origin); /* rr_region has been emptied by now */ dname = dname_parse(parser->rr_region, name); /* check if zone file contained a correct SOA record */ if (!parser->current_zone) { zc_error("zone configured as '%s' has no content.", name); } else if(!parser->current_zone->soa_rrset || parser->current_zone->soa_rrset->rr_count == 0) { zc_error("zone configured as '%s' has no SOA record.", name); } else if(dname_compare(domain_dname( parser->current_zone->soa_rrset->rrs[0].owner), dname) != 0) { zc_error("zone configured as '%s', but SOA has owner '%s'.", name, domain_to_string( parser->current_zone->soa_rrset->rrs[0].owner)); } region_free_all(parser->rr_region); parser_flush(); fclose(yyin); if(!zone_is_slave(zone->opts)) check_dname(zone); parser->filename = NULL; return parser->errors; }