summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nsd')
-rw-r--r--usr.sbin/nsd/answer.c2
-rw-r--r--usr.sbin/nsd/configlexer.lex1
-rw-r--r--usr.sbin/nsd/dbaccess.c45
-rw-r--r--usr.sbin/nsd/dbcreate.c27
-rw-r--r--usr.sbin/nsd/difffile.c56
-rw-r--r--usr.sbin/nsd/difffile.h6
-rw-r--r--usr.sbin/nsd/namedb.h11
-rw-r--r--usr.sbin/nsd/nsd-control.8.in2
-rw-r--r--usr.sbin/nsd/nsd-mem.c6
-rw-r--r--usr.sbin/nsd/nsd.conf.sample.in2
-rw-r--r--usr.sbin/nsd/options.c16
-rw-r--r--usr.sbin/nsd/options.h3
-rw-r--r--usr.sbin/nsd/packet.c10
-rw-r--r--usr.sbin/nsd/packet.h5
-rw-r--r--usr.sbin/nsd/remote.c17
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, &notexist)) {
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");