Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track $INCLUDE dependencies #377

Merged
merged 1 commit into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 54 additions & 15 deletions dbaccess.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ namedb_zone_create(namedb_type* db, const dname_type* dname,
zone->opts = zo;
zone->ixfr = NULL;
zone->filename = NULL;
zone->includes.count = 0;
zone->includes.paths = NULL;
zone->logstr = NULL;
zone->mtime.tv_sec = 0;
zone->mtime.tv_nsec = 0;
Expand All @@ -89,6 +91,34 @@ namedb_zone_create(namedb_type* db, const dname_type* dname,
return zone;
}

void
namedb_zone_free_filenames(namedb_type *db, zone_type* zone)
{
assert(!zone->includes.paths == !zone->includes.count);

if (zone->filename) {
region_recycle(
db->region, zone->filename, strlen(zone->filename) + 1);
zone->filename = NULL;
}

if (zone->includes.count) {
for (size_t i=0; i < zone->includes.count; i++) {
region_recycle(
db->region,
zone->includes.paths[i],
strlen(zone->includes.paths[i]) + 1);
}

region_recycle(
db->region,
zone->includes.paths,
zone->includes.count * sizeof(*zone->includes.paths));
zone->includes.count = 0;
zone->includes.paths = NULL;
}
}

void
namedb_zone_delete(namedb_type* db, zone_type* zone)
{
Expand Down Expand Up @@ -119,9 +149,7 @@ namedb_zone_delete(namedb_type* db, zone_type* zone)
hash_tree_delete(db->region, zone->dshashtree);
#endif
zone_ixfr_free(zone->ixfr);
if(zone->filename)
region_recycle(db->region, zone->filename,
strlen(zone->filename)+1);
namedb_zone_free_filenames(db, zone);
if(zone->logstr)
region_recycle(db->region, zone->logstr,
strlen(zone->logstr)+1);
Expand Down Expand Up @@ -236,12 +264,27 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
/* if zone_fname, then the file was acquired from reading it,
* and see if filename changed or mtime newer to read it */
} else if(zone_fname && strcmp(zone_fname, fname) == 0 &&
timespec_compare(&zone_mtime, &mtime) == 0) {
VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
fname));
return;
timespec_compare(&zone_mtime, &mtime) == 0) {
int changed = 0;
struct timespec include_mtime;
/* one of the includes may have been deleted, changed, etc */
for (size_t i=0; i < zone->includes.count; i++) {
if (!file_get_mtime(zone->includes.paths[i], &include_mtime, &nonexist)) {
changed = 1;
} else if (timespec_compare(&zone_mtime, &include_mtime) < 0) {
mtime = include_mtime;
changed = 1;
}
}

if (!changed) {
VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
fname));
return;
}
}
}

if(ixfr_create_from_difference(zone, fname,
&ixfr_create_already_done)) {
ixfrcr = ixfr_create_start(zone, fname,
Expand All @@ -252,6 +295,9 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
}
}

namedb_zone_free_filenames(nsd->db, zone);
zone->filename = region_strdup(nsd->db->region, fname);

/* wipe zone from memory */
#ifdef NSEC3
nsec3_clear_precompile(nsd->db, zone);
Expand All @@ -271,10 +317,7 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
zone->nsec3_param = NULL;
#endif
delete_zone_rrs(nsd->db, zone);
if(zone->filename)
region_recycle(nsd->db->region, zone->filename,
strlen(zone->filename)+1);
zone->filename = NULL;
namedb_zone_free_filenames(nsd->db, zone);
if(zone->logstr)
region_recycle(nsd->db->region, zone->logstr,
strlen(zone->logstr)+1);
Expand All @@ -286,10 +329,6 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
zone->is_changed = 0;
/* store zone into udb */
zone->mtime = mtime;
if(zone->filename)
region_recycle(nsd->db->region, zone->filename,
strlen(zone->filename)+1);
zone->filename = region_strdup(nsd->db->region, fname);
if(zone->logstr)
region_recycle(nsd->db->region, zone->logstr,
strlen(zone->logstr)+1);
Expand Down
5 changes: 1 addition & 4 deletions difffile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,10 +1396,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in,
region_recycle(nsd->db->region, zone->logstr,
strlen(zone->logstr)+1);
zone->logstr = region_strdup(nsd->db->region, log_buf);
if(zone->filename)
region_recycle(nsd->db->region, zone->filename,
strlen(zone->filename)+1);
zone->filename = NULL;
namedb_zone_free_filenames(nsd->db, zone);
if(softfail && taskudb && !is_axfr) {
log_msg(LOG_ERR, "Failed to apply IXFR cleanly "
"(deletes nonexistent RRs, adds existing RRs). "
Expand Down
3 changes: 3 additions & 0 deletions doc/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
format.
- Fix to initialize log_time_iso value in options.

23 August 2024: Jeroen
- Fix #57: Track $INCLUDEs in zone files

23 August 2024: Wouter
- Merge #376: Point the user towards tcpdump for logging individual
queries.
Expand Down
2 changes: 2 additions & 0 deletions doc/RELNOTES
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ FEATURES:
- Fix #383: log timestamps in ISO8601 format with timezone.
This adds the option `log-time-iso: yes` that logs in ISO8601
format.

BUG FIXES:
- Fix title underline and declaration after statement warnings.
- Add cross platform freebsd, openbsd and netbsd to github ci.
Expand All @@ -15,6 +16,7 @@ BUG FIXES:
prepended to fix detection.
- Merge #376: Point the user towards tcpdump for logging individual
queries.
- Track $INCLUDEs in zone files.
- Fix ci to update macos-12 to the macos-15 runner image.
- Merge #391: Update copyright lines (in version output).

Expand Down
8 changes: 7 additions & 1 deletion namedb.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,12 @@ struct zone
#endif
struct zone_options* opts;
struct zone_ixfr* ixfr;
char* filename; /* set if read from file, which file */
char *filename; /* set if read from file, which files */
/* list of include files to monitor for changes */
struct {
size_t count;
char **paths;
} includes;
char* logstr; /* set for zone xfer, the log string */
struct timespec mtime; /* time of last modification */
unsigned zonestatid; /* array index for zone stats */
Expand Down Expand Up @@ -400,6 +405,7 @@ namedb_find_or_create_zone(namedb_type *db, const dname_type *dname,
struct zone_options* zopt)
{ zone_type* zone = namedb_find_zone(db, dname);
return zone ? zone : namedb_zone_create(db, dname, zopt); }
void namedb_zone_free_filenames(namedb_type* db, zone_type* zone);
void namedb_zone_delete(namedb_type* db, zone_type* zone);
void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt);
void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options);
Expand Down
2 changes: 1 addition & 1 deletion simdzone
14 changes: 14 additions & 0 deletions tpkg/includes.tdir/includes.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
server:
zonesdir: ""
username: ""
chroot: ""
pidfile: nsd.pid
logfile: nsd.log
xfrdfile: nsd.xfrd
zonelistfile: "zone.list"
interface: 127.0.0.1
zonefiles-check: yes

zone:
name: example.com
zonefile: example.com
15 changes: 15 additions & 0 deletions tpkg/includes.tdir/includes.dsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
BaseName: includes
Version: 1.0
Description: Test for tracking include dependencies
CreationDate: Fri Aug 23 9:47:00 CET 2024
Maintainer: Jeroen Koekkoek
Category:
Component:
Depends:
Help:
Pre:
Post:
Test: includes.test
AuxFiles: includes.conf
Passed:
Failure:
60 changes: 60 additions & 0 deletions tpkg/includes.tdir/includes.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash
# #-- includes.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
. ../common.sh
get_random_port 1

# start NSD
PRE="../.."
NSD="$PRE/nsd"

example_com="
\$ORIGIN example.com.
\$INCLUDE example.com.soa
\$INCLUDE example.com.data
"

soa="@ IN SOA ns hostmaster 2024082300 6h 2h 7h 1h"

data="\$INCLUDE example.com.hosts"

hosts="www A 192.0.2.2"

echo "$example_com" > example.com
echo "$soa" > example.com.soa
echo "$data" > example.com.data
echo "$hosts" > example.com.hosts

$NSD -c includes.conf -p $RND_PORT
wait_nsd_up nsd.log
dig @127.0.0.1 -p $RND_PORT www.example.com
if dig @127.0.0.1 -p $RND_PORT www.example.com A | grep 192.0.2.2; then
echo "started successfully"
else
cat nsd.log
echo "failed to start"
kill_from_pidfile nsd.pid
exit 1
fi

hosts="www A 192.0.2.3"
echo "$hosts" > example.com.hosts
kill -1 `cat nsd.pid`

wait_logfile nsd.log "SIGHUP received, reloading..."
sleep 1
dig @127.0.0.1 -p $RND_PORT www.example.com
if dig @127.0.0.1 -p $RND_PORT www.example.com A | grep 192.0.2.3; then
echo "reloaded successfully"
else
cat nsd.log
echo "failed to reload"
kill_from_pidfile nsd.pid
exit 1
fi

kill_from_pidfile nsd.pid
rm -f example.com example.com.soa example.com.data example.com.hosts
38 changes: 38 additions & 0 deletions zonec.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,43 @@ int32_t zonec_accept(
return 0;
}

static int32_t zonec_include(
zone_parser_t *parser,
const char *file,
const char *path,
void *user_data)
{
char **paths;
struct zonec_state *state;
struct namedb *database;
struct zone *zone;

(void)parser;
(void)file;

state = (struct zonec_state *)user_data;
database = state->database;
zone = state->zone;

assert((zone->includes.count == 0) == (zone->includes.paths == NULL));

for (size_t i=0; i < zone->includes.count; i++)
if (strcmp(path, zone->includes.paths[i]) == 0)
return 0;

paths = region_alloc_array(
database->region, zone->includes.count + 1, sizeof(*paths));
if (zone->includes.count) {
const size_t size = zone->includes.count * sizeof(*paths);
memcpy(paths, zone->includes.paths, size);
region_recycle(database->region, zone->includes.paths, size);
}
paths[zone->includes.count] = region_strdup(database->region, path);
zone->includes.count++;
zone->includes.paths = paths;
return 0;
}

static void zonec_log(
zone_parser_t *parser,
uint32_t category,
Expand Down Expand Up @@ -395,6 +432,7 @@ zonec_read(
options.pretty_ttls = true; /* non-standard, for backwards compatibility */
options.log.callback = &zonec_log;
options.accept.callback = &zonec_accept;
options.include.callback = &zonec_include;

/* Parse and process all RRs. */
if (zone_parse(&parser, &options, &buffers, zonefile, &state) != 0) {
Expand Down