diff options
Diffstat (limited to 'usr.sbin/nsd')
-rw-r--r-- | usr.sbin/nsd/answer.c | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/configlexer.lex | 1 | ||||
-rw-r--r-- | usr.sbin/nsd/dbaccess.c | 45 | ||||
-rw-r--r-- | usr.sbin/nsd/dbcreate.c | 27 | ||||
-rw-r--r-- | usr.sbin/nsd/difffile.c | 56 | ||||
-rw-r--r-- | usr.sbin/nsd/difffile.h | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/namedb.h | 11 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-control.8.in | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-mem.c | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.conf.sample.in | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/options.c | 16 | ||||
-rw-r--r-- | usr.sbin/nsd/options.h | 3 | ||||
-rw-r--r-- | usr.sbin/nsd/packet.c | 10 | ||||
-rw-r--r-- | usr.sbin/nsd/packet.h | 5 | ||||
-rw-r--r-- | usr.sbin/nsd/remote.c | 17 |
15 files changed, 137 insertions, 72 deletions
diff --git a/usr.sbin/nsd/answer.c b/usr.sbin/nsd/answer.c index 0377f0b5859..be43c4c6cd1 100644 --- a/usr.sbin/nsd/answer.c +++ b/usr.sbin/nsd/answer.c @@ -34,7 +34,7 @@ answer_add_rrset(answer_type *answer, rr_section_type section, /* Don't add an RRset multiple times. */ for (i = 0; i < answer->rrset_count; ++i) { if (answer->rrsets[i] == rrset && - answer->domains[i] == domain) { + answer->domains[i]->number == domain->number) { if (section < answer->section[i]) { answer->section[i] = section; return 1; diff --git a/usr.sbin/nsd/configlexer.lex b/usr.sbin/nsd/configlexer.lex index ee4ad1522d9..c9f71fc38f4 100644 --- a/usr.sbin/nsd/configlexer.lex +++ b/usr.sbin/nsd/configlexer.lex @@ -116,6 +116,7 @@ ANY [^\"\n\r\\]|\\. server{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;} name{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NAME;} ip-address{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} +interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} ip-transparent{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;} debug-mode{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;} hide-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;} diff --git a/usr.sbin/nsd/dbaccess.c b/usr.sbin/nsd/dbaccess.c index 866c762ea70..8c215c9c578 100644 --- a/usr.sbin/nsd/dbaccess.c +++ b/usr.sbin/nsd/dbaccess.c @@ -29,6 +29,7 @@ #include "zonec.h" #include "nsec3.h" #include "difffile.h" +#include "nsd.h" static time_t udb_time = 0; static unsigned udb_rrsets = 0; @@ -471,16 +472,16 @@ file_get_mtime(const char* file, time_t* mtime, int* nonexist) } void -namedb_read_zonefile(struct namedb* db, struct zone* zone, udb_base* taskudb, +namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, udb_ptr* last_task) { time_t mtime = 0; int nonexist = 0; unsigned int errors; const char* fname; - if(!db || !db->udb || !zone || !zone->opts || !zone->opts->pattern->zonefile) + if(!nsd->db || !nsd->db->udb || !zone || !zone->opts || !zone->opts->pattern->zonefile) return; - fname = config_make_zonefile(zone->opts); + fname = config_make_zonefile(zone->opts, nsd); if(!file_get_mtime(fname, &mtime, &nonexist)) { if(nonexist) { VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist", @@ -488,11 +489,11 @@ namedb_read_zonefile(struct namedb* db, struct zone* zone, udb_base* taskudb, } else log_msg(LOG_ERR, "zonefile %s: %s", fname, strerror(errno)); - if(taskudb) task_new_soainfo(taskudb, last_task, zone); + if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); return; } else { /* check the mtime */ - if(udb_zone_get_mtime(db->udb, dname_name(domain_dname( + if(udb_zone_get_mtime(nsd->db->udb, dname_name(domain_dname( zone->apex)), domain_dname(zone->apex)->name_size) >= (uint64_t)mtime) { VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified", @@ -506,9 +507,9 @@ namedb_read_zonefile(struct namedb* db, struct zone* zone, udb_base* taskudb, #ifdef NSEC3 nsec3_hash_tree_clear(zone); #endif - delete_zone_rrs(db, zone); + delete_zone_rrs(nsd->db, zone); #ifdef NSEC3 - nsec3_clear_precompile(db, zone); + nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif /* NSEC3 */ errors = zonec_read(zone->opts->name, fname, zone); @@ -522,16 +523,16 @@ namedb_read_zonefile(struct namedb* db, struct zone* zone, udb_base* taskudb, #ifdef NSEC3 nsec3_hash_tree_clear(zone); #endif - delete_zone_rrs(db, zone); + delete_zone_rrs(nsd->db, zone); #ifdef NSEC3 - nsec3_clear_precompile(db, zone); + nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif /* NSEC3 */ /* see if we can revert to the udb stored version */ - if(!udb_zone_search(db->udb, &z, dname_name(domain_dname( + if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname( zone->apex)), domain_dname(zone->apex)->name_size)) { /* tell that zone contents has been lost */ - if(taskudb) task_new_soainfo(taskudb, last_task, zone); + if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); return; } /* read from udb */ @@ -539,47 +540,47 @@ namedb_read_zonefile(struct namedb* db, struct zone* zone, udb_base* taskudb, udb_rrsets = 0; udb_rrset_count = ZONE(&z)->rrset_count; udb_time = time(NULL); - read_zone_data(db->udb, db, dname_region, &z, zone); + read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone); region_destroy(dname_region); - udb_ptr_unlink(&z, db->udb); + udb_ptr_unlink(&z, nsd->db->udb); } else { VERBOSITY(1, (LOG_INFO, "zone %s read with no errors", zone->opts->name)); zone->is_ok = 1; zone->is_changed = 0; /* store zone into udb */ - if(!write_zone_to_udb(db->udb, zone, mtime)) { + if(!write_zone_to_udb(nsd->db->udb, zone, mtime)) { log_msg(LOG_ERR, "failed to store zone in db"); } else { VERBOSITY(2, (LOG_INFO, "zone %s written to db", zone->opts->name)); } } - if(taskudb) task_new_soainfo(taskudb, last_task, zone); + if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); #ifdef NSEC3 - prehash_zone_complete(db, zone); + prehash_zone_complete(nsd->db, zone); #endif } -void namedb_check_zonefile(struct namedb* db, udb_base* taskudb, +void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task, zone_options_t* zopt) { zone_type* zone; const dname_type* dname = (const dname_type*)zopt->node.key; /* find zone to go with it, or create it */ - zone = namedb_find_zone(db, dname); + zone = namedb_find_zone(nsd->db, dname); if(!zone) { - zone = namedb_zone_create(db, dname, zopt); + zone = namedb_zone_create(nsd->db, dname, zopt); } - namedb_read_zonefile(db, zone, taskudb, last_task); + namedb_read_zonefile(nsd, zone, taskudb, last_task); } -void namedb_check_zonefiles(struct namedb* db, nsd_options_t* opt, +void namedb_check_zonefiles(struct nsd* nsd, nsd_options_t* opt, udb_base* taskudb, udb_ptr* last_task) { zone_options_t* zo; /* check all zones in opt, create if not exist in main db */ RBTREE_FOR(zo, zone_options_t*, opt->zone_options) { - namedb_check_zonefile(db, taskudb, last_task, zo); + namedb_check_zonefile(nsd, taskudb, last_task, zo); } } diff --git a/usr.sbin/nsd/dbcreate.c b/usr.sbin/nsd/dbcreate.c index f0fbb112784..b764c7352cb 100644 --- a/usr.sbin/nsd/dbcreate.c +++ b/usr.sbin/nsd/dbcreate.c @@ -22,6 +22,7 @@ #include "udbradtree.h" #include "udbzone.h" #include "options.h" +#include "nsd.h" /* pathname directory separator character */ #define PATHSEP '/' @@ -44,6 +45,8 @@ add_rdata(rr_type* rr, unsigned i, uint8_t* buf, size_t buflen) default: break; } + if(rdata_atom_size(rr->rdatas[i]) > buflen) + return 0; memmove(buf, rdata_atom_data(rr->rdatas[i]), rdata_atom_size(rr->rdatas[i])); return rdata_atom_size(rr->rdatas[i]); @@ -313,7 +316,7 @@ create_path_components(const char* path, int* notexist) } void -namedb_write_zonefile(namedb_type* db, zone_options_t* zopt) +namedb_write_zonefile(struct nsd* nsd, zone_options_t* zopt) { const char* zfile; int notexist = 0; @@ -322,12 +325,12 @@ namedb_write_zonefile(namedb_type* db, zone_options_t* zopt) * configured, then no need to write data to disk */ if(!zopt->pattern->zonefile) return; - zone = namedb_find_zone(db, (const dname_type*)zopt->node.key); + zone = namedb_find_zone(nsd->db, (const dname_type*)zopt->node.key); if(!zone || !zone->apex) return; /* write if file does not exist, or if changed */ /* so, determine filename, create directory components, check exist*/ - zfile = config_make_zonefile(zopt); + zfile = config_make_zonefile(zopt, nsd); if(!create_path_components(zfile, ¬exist)) { log_msg(LOG_ERR, "could not write zone %s to file %s because " "the path could not be created", zopt->name, zfile); @@ -339,7 +342,7 @@ namedb_write_zonefile(namedb_type* db, zone_options_t* zopt) char logs[4096]; char bakfile[4096]; udb_ptr zudb; - if(!udb_zone_search(db->udb, &zudb, + if(!udb_zone_search(nsd->db->udb, &zudb, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size)) return; /* zone does not exist in db */ @@ -347,33 +350,33 @@ namedb_write_zonefile(namedb_type* db, zone_options_t* zopt) snprintf(bakfile, sizeof(bakfile), "%s~", zfile); if(ZONE(&zudb)->log_str.data) { udb_ptr s; - udb_ptr_new(&s, db->udb, &ZONE(&zudb)->log_str); + udb_ptr_new(&s, nsd->db->udb, &ZONE(&zudb)->log_str); strlcpy(logs, (char*)udb_ptr_data(&s), sizeof(logs)); - udb_ptr_unlink(&s, db->udb); + udb_ptr_unlink(&s, nsd->db->udb); } else logs[0] = 0; if(!write_to_zonefile(zone, bakfile, logs)) { - udb_ptr_unlink(&zudb, db->udb); + udb_ptr_unlink(&zudb, nsd->db->udb); return; /* error already printed */ } if(rename(bakfile, zfile) == -1) { log_msg(LOG_ERR, "rename(%s to %s) failed: %s", bakfile, zfile, strerror(errno)); - udb_ptr_unlink(&zudb, db->udb); + udb_ptr_unlink(&zudb, nsd->db->udb); return; } zone->is_changed = 0; ZONE(&zudb)->mtime = (uint64_t)time(0); ZONE(&zudb)->is_changed = 0; - udb_zone_set_log_str(db->udb, &zudb, NULL); - udb_ptr_unlink(&zudb, db->udb); + udb_zone_set_log_str(nsd->db->udb, &zudb, NULL); + udb_ptr_unlink(&zudb, nsd->db->udb); } } void -namedb_write_zonefiles(namedb_type* db, nsd_options_t* options) +namedb_write_zonefiles(struct nsd* nsd, nsd_options_t* options) { zone_options_t* zo; RBTREE_FOR(zo, zone_options_t*, options->zone_options) { - namedb_write_zonefile(db, zo); + namedb_write_zonefile(nsd, zo); } } diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c index 0719cf6f9dc..08f213c22c7 100644 --- a/usr.sbin/nsd/difffile.c +++ b/usr.sbin/nsd/difffile.c @@ -472,6 +472,7 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone) } if(domain != zone->apex && domain->nsec3 && domain->nsec3->dshash_node.key && + (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) && !nsec3_condition_dshash(domain, zone)) { /* remove precompile */ domain->nsec3->nsec3_ds_parent_cover = NULL; @@ -606,7 +607,7 @@ int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, - region_type* temp_region, udb_ptr* udbz) + region_type* temp_region, udb_ptr* udbz, int* softfail) { domain_type *domain; rrset_type *rrset; @@ -615,6 +616,7 @@ delete_RR(namedb_type* db, const dname_type* dname, log_msg(LOG_WARNING, "diff: domain %s does not exist", dname_to_string(dname,0)); buffer_skip(packet, rdatalen); + *softfail = 1; return 1; /* not fatal error */ } rrset = domain_find_rrset(domain, zone, type); @@ -622,6 +624,7 @@ delete_RR(namedb_type* db, const dname_type* dname, log_msg(LOG_WARNING, "diff: rrset %s does not exist", dname_to_string(dname,0)); buffer_skip(packet, rdatalen); + *softfail = 1; return 1; /* not fatal error */ } else { /* find the RR in the rrset */ @@ -641,9 +644,13 @@ delete_RR(namedb_type* db, const dname_type* dname, return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0); + if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex + && rrset->rr_count != 0) + rrnum = 0; /* replace existing SOA if no match */ if(rrnum == -1) { log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist", dname_to_string(dname,0), rrtype_to_string(type)); + *softfail = 1; return 1; /* not fatal error */ } /* delete the normalized RR from the udb */ @@ -713,7 +720,8 @@ delete_RR(namedb_type* db, const dname_type* dname, 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, udb_ptr* udbz) + buffer_type* packet, size_t rdatalen, zone_type *zone, udb_ptr* udbz, + int* softfail) { domain_type* domain; rrset_type* rrset; @@ -757,6 +765,7 @@ add_RR(namedb_type* db, const dname_type* dname, 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 */ + *softfail = 1; return 1; } @@ -899,7 +908,8 @@ static int apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, nsd_options_t* opt, uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, - udb_ptr* udbz, struct zone** zone_res, const char* patname, int* bytes) + udb_ptr* udbz, struct zone** zone_res, const char* patname, int* bytes, + int* softfail) { uint32_t msglen, checklen, pkttype; int qcount, ancount, counter; @@ -1114,7 +1124,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, * 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 " + log_msg(LOG_ERR, "%s SOA serial %u is not " "in memory, skip IXFR", zone, serialno); region_destroy(region); /* break out and stop the IXFR, ignore it */ @@ -1146,7 +1156,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, continue; /* do not delete final SOA RR for IXFR */ } if(!delete_RR(db, dname, type, klass, packet, - rrlen, zone_db, region, udbz)) { + rrlen, zone_db, region, udbz, softfail)) { region_destroy(region); return 0; } @@ -1155,7 +1165,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, { /* add this rr */ if(!add_RR(db, dname, type, klass, ttl, packet, - rrlen, zone_db, udbz)) { + rrlen, zone_db, udbz, softfail)) { region_destroy(region); return 0; } @@ -1256,7 +1266,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, if(committed) { - int is_axfr=0, delete_mode=0, rr_count=0; + int is_axfr=0, delete_mode=0, rr_count=0, softfail=0; const dname_type* apex = zonedb->apex->dname; udb_ptr z; @@ -1286,7 +1296,8 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i)); ret = apply_ixfr(nsd->db, in, zone_buf, new_serial, opt, i, num_parts, &is_axfr, &delete_mode, - &rr_count, &z, &zonedb, patname_buf, &num_bytes); + &rr_count, &z, &zonedb, patname_buf, &num_bytes, + &softfail); if(ret == 0) { log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf); xfrd_unlink_xfrfile(nsd, xfrfilenr); @@ -1311,7 +1322,17 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, ZONE(&z)->mtime = time_end_0; udb_zone_set_log_str(nsd->db->udb, &z, log_buf); udb_ptr_unlink(&z, nsd->db->udb); - if(taskudb) task_new_soainfo(taskudb, last_task, zonedb); + if(softfail && taskudb && !is_axfr) { + log_msg(LOG_ERR, "Failed to apply IXFR cleanly " + "(deletes nonexistent RRs, adds existing RRs). " + "Zone %s contents is different from master, " + "starting AXFR. Transfer %s", zone_buf, log_buf); + /* add/del failures in IXFR, get an AXFR */ + task_new_soainfo(taskudb, last_task, zonedb, 1); + } else { + if(taskudb) + task_new_soainfo(taskudb, last_task, zonedb, 0); + } if(1 <= verbosity) { double elapsed = (double)(time_end_0 - time_start_0)+ @@ -1359,7 +1380,8 @@ task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e, return 1; } -void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z) +void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z, + int gone) { /* calculate size */ udb_ptr e; @@ -1372,7 +1394,7 @@ void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z) domain_to_string(z->apex))); apex = domain_dname(z->apex); sz = sizeof(struct task_list_d) + dname_total_size(apex); - if(z->soa_rrset) { + if(z->soa_rrset && !gone) { ns = domain_dname(rdata_atom_domain( z->soa_rrset->rrs[0].rdatas[0])); em = domain_dname(rdata_atom_domain( @@ -1391,7 +1413,7 @@ void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z) } TASKLIST(&e)->task_type = task_soa_info; - if(z->soa_rrset) { + if(z->soa_rrset && !gone) { uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl); uint8_t* p = (uint8_t*)TASKLIST(&e)->zname; p += dname_total_size(apex); @@ -1729,10 +1751,10 @@ task_process_checkzones(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, zone_options_t* zo = zone_options_find(nsd->options, task->zname); if(zo) - namedb_check_zonefile(nsd->db, udb, last_task, zo); + namedb_check_zonefile(nsd, udb, last_task, zo); } else { /* check all zones */ - namedb_check_zonefiles(nsd->db, nsd->options, udb, last_task); + namedb_check_zonefiles(nsd, nsd->options, udb, last_task); } } @@ -1743,9 +1765,9 @@ task_process_writezones(struct nsd* nsd, struct task_list_d* task) zone_options_t* zo = zone_options_find(nsd->options, task->zname); if(zo) - namedb_write_zonefile(nsd->db, zo); + namedb_write_zonefile(nsd, zo); } else { - namedb_write_zonefiles(nsd->db, nsd->options); + namedb_write_zonefiles(nsd, nsd->options); } } @@ -1773,7 +1795,7 @@ task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, } /* if zone is empty, attempt to read the zonefile from disk (if any) */ if(!z->soa_rrset && z->opts->pattern->zonefile) { - namedb_read_zonefile(nsd->db, z, udb, last_task); + namedb_read_zonefile(nsd, z, udb, last_task); } } diff --git a/usr.sbin/nsd/difffile.h b/usr.sbin/nsd/difffile.h index d5f2cb8833f..e6a5d4eed17 100644 --- a/usr.sbin/nsd/difffile.h +++ b/usr.sbin/nsd/difffile.h @@ -46,12 +46,12 @@ void delete_zone_rrs(namedb_type* db, zone_type* zone); int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, - region_type* temp_region, struct udb_ptr* udbz); + region_type* temp_region, struct udb_ptr* udbz, int* softfail); /* add an RR */ 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, - struct udb_ptr* udbz); + struct udb_ptr* udbz, int* softfail); /* task udb structure */ struct task_list_d { @@ -104,7 +104,7 @@ struct udb_base* task_file_create(const char* file); void task_remap(udb_base* udb); void task_process_sync(udb_base* udb); void task_clear(udb_base* udb); -void task_new_soainfo(udb_base* udb, udb_ptr* last, struct zone* z); +void task_new_soainfo(udb_base* udb, udb_ptr* last, struct zone* z, int gone); void task_new_expire(udb_base* udb, udb_ptr* last, const struct dname* z, int expired); void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat, diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index dc0cb3fbff7..1c41e5e4991 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -20,6 +20,7 @@ struct zone_options; struct nsd_options; struct udb_base; struct udb_ptr; +struct nsd; typedef union rdata_atom rdata_atom_type; typedef struct rrset rrset_type; @@ -342,20 +343,20 @@ int namedb_lookup (struct namedb* db, struct namedb *namedb_open(const char *filename, struct nsd_options* opt); void namedb_close_udb(struct namedb* db); void namedb_close(struct namedb* db); -void namedb_check_zonefiles(struct namedb* db, struct nsd_options* opt, +void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, struct udb_base* taskudb, struct udb_ptr* last_task); -void namedb_check_zonefile(struct namedb* db, struct udb_base* taskudb, +void namedb_check_zonefile(struct nsd* nsd, struct udb_base* taskudb, struct udb_ptr* last_task, struct zone_options* zo); /** zone one zonefile into memory and revert on parse error, write to udb */ -void namedb_read_zonefile(struct namedb* db, struct zone* zone, +void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, struct udb_base* taskudb, struct udb_ptr* last_task); void apex_rrset_checks(struct namedb* db, rrset_type* rrset, domain_type* domain); zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, struct zone_options* zopt); void namedb_zone_delete(namedb_type* db, zone_type* zone); -void namedb_write_zonefile(namedb_type* db, struct zone_options* zopt); -void namedb_write_zonefiles(namedb_type* db, struct nsd_options* options); +void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt); +void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options); int create_dirs(const char* path); void allocate_domain_nsec3(domain_table_type *table, domain_type *result); diff --git a/usr.sbin/nsd/nsd-control.8.in b/usr.sbin/nsd/nsd-control.8.in index bf610f1097b..b9a32c36a07 100644 --- a/usr.sbin/nsd/nsd-control.8.in +++ b/usr.sbin/nsd/nsd-control.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-control" "8" "Oct 29, 2013" "NLnet Labs" "nsd 4.0.0" +.TH "nsd\-control" "8" "Jan 27, 2014" "NLnet Labs" "nsd 4.0.1" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-mem.c b/usr.sbin/nsd/nsd-mem.c index 0981eafef73..e47bb9add1e 100644 --- a/usr.sbin/nsd/nsd-mem.c +++ b/usr.sbin/nsd/nsd-mem.c @@ -192,6 +192,7 @@ static void check_zone_mem(const char* tf, const char* df, zone_options_t* zo, nsd_options_t* opt, struct tot_mem* totmem) { + struct nsd nsd; struct namedb* db; const dname_type* dname = (const dname_type*)zo->node.key; zone_type* zone; @@ -203,14 +204,15 @@ check_zone_mem(const char* tf, const char* df, zone_options_t* zo, /* init*/ memset(&zmem, 0, sizeof(zmem)); - db = namedb_open(df, opt); + memset(&nsd, 0, sizeof(nsd)); + nsd.db = db = namedb_open(df, opt); if(!db) error("cannot open %s: %s", df, strerror(errno)); zone = namedb_zone_create(db, dname, zo); taskudb = udb_base_create_new(tf, &namedb_walkfunc, NULL); udb_ptr_init(&last_task, taskudb); /* read the zone */ - namedb_read_zonefile(db, zone, taskudb, &last_task); + namedb_read_zonefile(&nsd, zone, taskudb, &last_task); /* account the memory for this zone */ account_zone(db, &zmem); diff --git a/usr.sbin/nsd/nsd.conf.sample.in b/usr.sbin/nsd/nsd.conf.sample.in index 002d40e7065..aa0ab38a9fc 100644 --- a/usr.sbin/nsd/nsd.conf.sample.in +++ b/usr.sbin/nsd/nsd.conf.sample.in @@ -78,7 +78,7 @@ server: # identify the server (CH TXT ID.SERVER entry). # identity: "unidentified server" - # NSID identity (hex string). default disabled. + # NSID identity (hex string, or "ascii_somestring"). default disabled. # nsid: "aabbccdd" # Maximum number of concurrent TCP connections per server. diff --git a/usr.sbin/nsd/options.c b/usr.sbin/nsd/options.c index 221a0f7eb35..060e5eba2bc 100644 --- a/usr.sbin/nsd/options.c +++ b/usr.sbin/nsd/options.c @@ -1543,12 +1543,20 @@ replace_str(char* str, size_t len, const char* one, const char* two) } const char* -config_make_zonefile(zone_options_t* zone) +config_make_zonefile(zone_options_t* zone, struct nsd* nsd) { static char f[1024]; /* if not a template, return as-is */ - if(!strchr(zone->pattern->zonefile, '%')) + if(!strchr(zone->pattern->zonefile, '%')) { + if (nsd->chrootdir && nsd->chrootdir[0] && + zone->pattern->zonefile && + zone->pattern->zonefile[0] == '/' && + strncmp(zone->pattern->zonefile, nsd->chrootdir, + strlen(nsd->chrootdir)) == 0) + /* -1 because chrootdir ends in trailing slash */ + return zone->pattern->zonefile + strlen(nsd->chrootdir) - 1; return zone->pattern->zonefile; + } strlcpy(f, zone->pattern->zonefile, sizeof(f)); if(strstr(f, "%1")) replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); @@ -1564,6 +1572,10 @@ config_make_zonefile(zone_options_t* zone) replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); if(strstr(f, "%s")) replace_str(f, sizeof(f), "%s", zone->name); + if (nsd->chrootdir && nsd->chrootdir[0] && f[0] == '/' && + strncmp(f, nsd->chrootdir, strlen(nsd->chrootdir)) == 0) + /* -1 because chrootdir ends in trailing slash */ + return f + strlen(nsd->chrootdir) - 1; return f; } diff --git a/usr.sbin/nsd/options.h b/usr.sbin/nsd/options.h index 4cad972a683..062ac2842c8 100644 --- a/usr.sbin/nsd/options.h +++ b/usr.sbin/nsd/options.h @@ -18,6 +18,7 @@ struct query; struct dname; struct tsig_key; struct buffer; +struct nsd; typedef struct nsd_options nsd_options_t; typedef struct pattern_options pattern_options_t; @@ -322,7 +323,7 @@ int acl_equal(acl_options_t* p, acl_options_t* q); /* see if a zone is a slave or a master zone */ int zone_is_slave(zone_options_t* opt); /* create zonefile name, returns static pointer (perhaps to options data) */ -const char* config_make_zonefile(zone_options_t* zone); +const char* config_make_zonefile(zone_options_t* zone, struct nsd* nsd); #define ZONEC_PCT_TIME 5 /* seconds, then it starts to print pcts */ #define ZONEC_PCT_COUNT 100000 /* elements before pct check is done */ diff --git a/usr.sbin/nsd/packet.c b/usr.sbin/nsd/packet.c index 4cba1600c8f..72ae4cedf03 100644 --- a/usr.sbin/nsd/packet.c +++ b/usr.sbin/nsd/packet.c @@ -44,7 +44,7 @@ encode_dname(query_type *q, domain_type *domain) } int -packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr) +packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr, uint32_t ttl) { size_t truncation_mark; uint16_t rdlength = 0; @@ -64,7 +64,7 @@ packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr) encode_dname(q, owner); buffer_write_u16(q->packet, rr->type); buffer_write_u16(q->packet, rr->klass); - buffer_write_u32(q->packet, rr->ttl); + buffer_write_u32(q->packet, ttl); /* Reserve space for rdlength. */ rdlength_pos = buffer_position(q->packet); @@ -137,7 +137,8 @@ packet_encode_rrset(query_type *query, truncation_mark = buffer_position(query->packet); for (i = 0; i < rrset->rr_count; ++i) { - if (packet_encode_rr(query, owner, &rrset->rrs[i])) { + if (packet_encode_rr(query, owner, &rrset->rrs[i], + rrset->rrs[i].ttl)) { ++added; } else { all_added = 0; @@ -156,7 +157,8 @@ packet_encode_rrset(query_type *query, == rrset_rrtype(rrset)) { if (packet_encode_rr(query, owner, - &rrsig->rrs[i])) + &rrsig->rrs[i], + rrset_rrtype(rrset)==TYPE_SOA?rrset->rrs[0].ttl:rrsig->rrs[i].ttl)) { ++added; } else { diff --git a/usr.sbin/nsd/packet.h b/usr.sbin/nsd/packet.h index 2efa288b91e..47558394e0d 100644 --- a/usr.sbin/nsd/packet.h +++ b/usr.sbin/nsd/packet.h @@ -147,7 +147,10 @@ struct query; * Encode RR with OWNER as owner name into QUERY. Returns the number * of RRs successfully encoded. */ -int packet_encode_rr(struct query *query, domain_type *owner, rr_type *rr); +int packet_encode_rr(struct query *query, + domain_type *owner, + rr_type *rr, + uint32_t ttl); /* * Encode RRSET with OWNER as the owner name into QUERY. Returns the diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c index d4858d2202a..2eb9abd86bb 100644 --- a/usr.sbin/nsd/remote.c +++ b/usr.sbin/nsd/remote.c @@ -51,6 +51,9 @@ #ifdef HAVE_OPENSSL_ERR_H #include <openssl/err.h> #endif +#ifdef HAVE_OPENSSL_RAND_H +#include <openssl/rand.h> +#endif #include <ctype.h> #include <unistd.h> #include <assert.h> @@ -234,6 +237,20 @@ daemon_remote_create(nsd_options_t* cfg) OpenSSL_add_all_algorithms(); (void)SSL_library_init(); + if(!RAND_status()) { + /* try to seed it */ + unsigned char buf[256]; + unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); + size_t i; + v = seed; + for(i=0; i<256/sizeof(v); i++) { + memmove(buf+i*sizeof(v), &v, sizeof(v)); + v = v*seed + (unsigned int)i; + } + RAND_seed(buf, 256); + log_msg(LOG_WARNING, "warning: no entropy, seeding openssl PRNG with time"); + } + rc->ctx = SSL_CTX_new(SSLv23_server_method()); if(!rc->ctx) { log_crypto_err("could not SSL_CTX_new"); |