1d83a80eeSchristos /*
2d83a80eeSchristos * dbaccess.c -- access methods for nsd(8) database
3d83a80eeSchristos *
4d83a80eeSchristos * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5d83a80eeSchristos *
6d83a80eeSchristos * See LICENSE for the license.
7d83a80eeSchristos *
8d83a80eeSchristos */
9d83a80eeSchristos
10d83a80eeSchristos #include "config.h"
11d83a80eeSchristos
12d83a80eeSchristos #include <sys/types.h>
13d83a80eeSchristos #include <sys/stat.h>
14d83a80eeSchristos
15d83a80eeSchristos #include <errno.h>
16d83a80eeSchristos #include <stdlib.h>
17d83a80eeSchristos #include <string.h>
18d83a80eeSchristos #include <unistd.h>
19d83a80eeSchristos #include <fcntl.h>
20d83a80eeSchristos
21d83a80eeSchristos #include "dns.h"
22d83a80eeSchristos #include "namedb.h"
23d83a80eeSchristos #include "util.h"
24d83a80eeSchristos #include "options.h"
25d83a80eeSchristos #include "rdata.h"
26d83a80eeSchristos #include "udb.h"
27d83a80eeSchristos #include "zonec.h"
28d83a80eeSchristos #include "nsec3.h"
29d83a80eeSchristos #include "difffile.h"
30d83a80eeSchristos #include "nsd.h"
31ee758998Schristos #include "ixfr.h"
32ee758998Schristos #include "ixfrcreate.h"
33d83a80eeSchristos
34d83a80eeSchristos void
namedb_close(struct namedb * db)35d83a80eeSchristos namedb_close(struct namedb* db)
36d83a80eeSchristos {
37d83a80eeSchristos if(db) {
38d83a80eeSchristos zonec_desetup_parser();
39d83a80eeSchristos region_destroy(db->region);
40d83a80eeSchristos }
41d83a80eeSchristos }
42d83a80eeSchristos
43d83a80eeSchristos void
namedb_free_ixfr(struct namedb * db)44ee758998Schristos namedb_free_ixfr(struct namedb* db)
45d83a80eeSchristos {
46ee758998Schristos struct radnode* n;
47ee758998Schristos for(n=radix_first(db->zonetree); n; n=radix_next(n)) {
48ee758998Schristos zone_ixfr_free(((zone_type*)n->elem)->ixfr);
49d83a80eeSchristos }
50d83a80eeSchristos }
51d83a80eeSchristos
52d83a80eeSchristos /** create a zone */
53d83a80eeSchristos zone_type*
namedb_zone_create(namedb_type * db,const dname_type * dname,struct zone_options * zo)54d83a80eeSchristos namedb_zone_create(namedb_type* db, const dname_type* dname,
553fb62404Schristos struct zone_options* zo)
56d83a80eeSchristos {
57d83a80eeSchristos zone_type* zone = (zone_type *) region_alloc(db->region,
58d83a80eeSchristos sizeof(zone_type));
59d83a80eeSchristos zone->node = radname_insert(db->zonetree, dname_name(dname),
60d83a80eeSchristos dname->name_size, zone);
61d83a80eeSchristos assert(zone->node);
62d83a80eeSchristos zone->apex = domain_table_insert(db->domains, dname);
63d83a80eeSchristos zone->apex->usage++; /* the zone.apex reference */
64d83a80eeSchristos zone->apex->is_apex = 1;
65d83a80eeSchristos zone->soa_rrset = NULL;
66d83a80eeSchristos zone->soa_nx_rrset = NULL;
67d83a80eeSchristos zone->ns_rrset = NULL;
68d83a80eeSchristos #ifdef NSEC3
69d83a80eeSchristos zone->nsec3_param = NULL;
70d83a80eeSchristos zone->nsec3_last = NULL;
71d83a80eeSchristos zone->nsec3tree = NULL;
72d83a80eeSchristos zone->hashtree = NULL;
73d83a80eeSchristos zone->wchashtree = NULL;
74d83a80eeSchristos zone->dshashtree = NULL;
75d83a80eeSchristos #endif
76d83a80eeSchristos zone->opts = zo;
77ee758998Schristos zone->ixfr = NULL;
78d83a80eeSchristos zone->filename = NULL;
79d83a80eeSchristos zone->logstr = NULL;
80d83a80eeSchristos zone->mtime.tv_sec = 0;
81d83a80eeSchristos zone->mtime.tv_nsec = 0;
82d83a80eeSchristos zone->zonestatid = 0;
83d83a80eeSchristos zone->is_secure = 0;
84d83a80eeSchristos zone->is_changed = 0;
85ee758998Schristos zone->is_updated = 0;
86ee758998Schristos zone->is_skipped = 0;
87ee758998Schristos zone->is_checked = 0;
88ee758998Schristos zone->is_bad = 0;
89d83a80eeSchristos zone->is_ok = 1;
90d83a80eeSchristos return zone;
91d83a80eeSchristos }
92d83a80eeSchristos
93d83a80eeSchristos void
namedb_zone_delete(namedb_type * db,zone_type * zone)94d83a80eeSchristos namedb_zone_delete(namedb_type* db, zone_type* zone)
95d83a80eeSchristos {
96d83a80eeSchristos /* RRs and UDB and NSEC3 and so on must be already deleted */
97d83a80eeSchristos radix_delete(db->zonetree, zone->node);
98d83a80eeSchristos
99d83a80eeSchristos /* see if apex can be deleted */
100d83a80eeSchristos if(zone->apex) {
101d83a80eeSchristos zone->apex->usage --;
102d83a80eeSchristos zone->apex->is_apex = 0;
103d83a80eeSchristos if(zone->apex->usage == 0) {
104d83a80eeSchristos /* delete the apex, possibly */
105d83a80eeSchristos domain_table_deldomain(db, zone->apex);
106d83a80eeSchristos }
107d83a80eeSchristos }
108d83a80eeSchristos
109d83a80eeSchristos /* soa_rrset is freed when the SOA was deleted */
110d83a80eeSchristos if(zone->soa_nx_rrset) {
111d83a80eeSchristos region_recycle(db->region, zone->soa_nx_rrset->rrs,
112d83a80eeSchristos sizeof(rr_type));
113d83a80eeSchristos region_recycle(db->region, zone->soa_nx_rrset,
114d83a80eeSchristos sizeof(rrset_type));
115d83a80eeSchristos }
116d83a80eeSchristos #ifdef NSEC3
117d83a80eeSchristos hash_tree_delete(db->region, zone->nsec3tree);
118d83a80eeSchristos hash_tree_delete(db->region, zone->hashtree);
119d83a80eeSchristos hash_tree_delete(db->region, zone->wchashtree);
120d83a80eeSchristos hash_tree_delete(db->region, zone->dshashtree);
121d83a80eeSchristos #endif
122ee758998Schristos zone_ixfr_free(zone->ixfr);
123d83a80eeSchristos if(zone->filename)
124d83a80eeSchristos region_recycle(db->region, zone->filename,
125d83a80eeSchristos strlen(zone->filename)+1);
126d83a80eeSchristos if(zone->logstr)
127d83a80eeSchristos region_recycle(db->region, zone->logstr,
128d83a80eeSchristos strlen(zone->logstr)+1);
129d83a80eeSchristos region_recycle(db->region, zone, sizeof(zone_type));
130d83a80eeSchristos }
131d83a80eeSchristos
132d83a80eeSchristos struct namedb *
namedb_open(struct nsd_options * opt)133*811a4a01Schristos namedb_open (struct nsd_options* opt)
134d83a80eeSchristos {
135d83a80eeSchristos namedb_type* db;
136d83a80eeSchristos
137d83a80eeSchristos /*
138d83a80eeSchristos * Region used to store the loaded database. The region is
139d83a80eeSchristos * freed in namedb_close.
140d83a80eeSchristos */
141d83a80eeSchristos region_type* db_region;
142*811a4a01Schristos
143*811a4a01Schristos (void)opt;
144d83a80eeSchristos
145d83a80eeSchristos #ifdef USE_MMAP_ALLOC
146d83a80eeSchristos db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE,
147d83a80eeSchristos MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1);
148d83a80eeSchristos #else /* !USE_MMAP_ALLOC */
149d83a80eeSchristos db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE,
150d83a80eeSchristos DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1);
151d83a80eeSchristos #endif /* !USE_MMAP_ALLOC */
152d83a80eeSchristos db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb));
153d83a80eeSchristos db->region = db_region;
154d83a80eeSchristos db->domains = domain_table_create(db->region);
155d83a80eeSchristos db->zonetree = radix_tree_create(db->region);
156d83a80eeSchristos db->diff_skip = 0;
157d83a80eeSchristos db->diff_pos = 0;
158d83a80eeSchristos zonec_setup_parser(db);
159d83a80eeSchristos
160d83a80eeSchristos if (gettimeofday(&(db->diff_timestamp), NULL) != 0) {
161*811a4a01Schristos log_msg(LOG_ERR, "unable to load namedb: cannot initialize timestamp");
162d83a80eeSchristos region_destroy(db_region);
163d83a80eeSchristos return NULL;
164d83a80eeSchristos }
165d83a80eeSchristos
166d83a80eeSchristos return db;
167d83a80eeSchristos }
168d83a80eeSchristos
169ee758998Schristos /** get the file mtime stat (or nonexist or error) */
170d83a80eeSchristos int
file_get_mtime(const char * file,struct timespec * mtime,int * nonexist)171d83a80eeSchristos file_get_mtime(const char* file, struct timespec* mtime, int* nonexist)
172d83a80eeSchristos {
173d83a80eeSchristos struct stat s;
174d83a80eeSchristos if(stat(file, &s) != 0) {
175d83a80eeSchristos mtime->tv_sec = 0;
176d83a80eeSchristos mtime->tv_nsec = 0;
177d83a80eeSchristos *nonexist = (errno == ENOENT);
178d83a80eeSchristos return 0;
179d83a80eeSchristos }
180d83a80eeSchristos *nonexist = 0;
181d83a80eeSchristos mtime->tv_sec = s.st_mtime;
182d83a80eeSchristos #ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
183d83a80eeSchristos mtime->tv_nsec = s.st_mtimensec;
184d83a80eeSchristos #elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
185d83a80eeSchristos mtime->tv_nsec = s.st_mtim.tv_nsec;
186d83a80eeSchristos #else
187d83a80eeSchristos mtime->tv_nsec = 0;
188d83a80eeSchristos #endif
189d83a80eeSchristos return 1;
190d83a80eeSchristos }
191d83a80eeSchristos
192d83a80eeSchristos void
namedb_read_zonefile(struct nsd * nsd,struct zone * zone,udb_base * taskudb,udb_ptr * last_task)193d83a80eeSchristos namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
194d83a80eeSchristos udb_ptr* last_task)
195d83a80eeSchristos {
196d83a80eeSchristos struct timespec mtime;
197d83a80eeSchristos int nonexist = 0;
198d83a80eeSchristos unsigned int errors;
199d83a80eeSchristos const char* fname;
200ee758998Schristos struct ixfr_create* ixfrcr = NULL;
201ee758998Schristos int ixfr_create_already_done = 0;
202d83a80eeSchristos if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile)
203d83a80eeSchristos return;
204d83a80eeSchristos mtime.tv_sec = 0;
205d83a80eeSchristos mtime.tv_nsec = 0;
206d83a80eeSchristos fname = config_make_zonefile(zone->opts, nsd);
207f3d63a56Schristos assert(fname);
208d83a80eeSchristos if(!file_get_mtime(fname, &mtime, &nonexist)) {
209d83a80eeSchristos if(nonexist) {
210ee758998Schristos if(zone_is_slave(zone->opts)) {
211ee758998Schristos /* for slave zones not as bad, no zonefile
212ee758998Schristos * may just mean we have to transfer it */
213d83a80eeSchristos VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist",
214d83a80eeSchristos fname));
215ee758998Schristos } else {
216ee758998Schristos /* without a download option, we can never
217ee758998Schristos * serve data, more severe error printout */
218ee758998Schristos log_msg(LOG_ERR, "zonefile %s does not exist", fname);
219ee758998Schristos }
220ee758998Schristos
221d83a80eeSchristos } else
222d83a80eeSchristos log_msg(LOG_ERR, "zonefile %s: %s",
223d83a80eeSchristos fname, strerror(errno));
224d83a80eeSchristos if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
225d83a80eeSchristos return;
226d83a80eeSchristos } else {
227d83a80eeSchristos const char* zone_fname = zone->filename;
228d83a80eeSchristos struct timespec zone_mtime = zone->mtime;
229d83a80eeSchristos /* if no zone_fname, then it was acquired in zone transfer,
230d83a80eeSchristos * see if the file is newer than the zone transfer
231d83a80eeSchristos * (regardless if this is a different file), because the
232d83a80eeSchristos * zone transfer is a different content source too */
233d83a80eeSchristos if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) {
234d83a80eeSchristos VERBOSITY(3, (LOG_INFO, "zonefile %s is older than "
235d83a80eeSchristos "zone transfer in memory", fname));
236d83a80eeSchristos return;
237d83a80eeSchristos
238d83a80eeSchristos /* if zone_fname, then the file was acquired from reading it,
239d83a80eeSchristos * and see if filename changed or mtime newer to read it */
240f3d63a56Schristos } else if(zone_fname && strcmp(zone_fname, fname) == 0 &&
241d83a80eeSchristos timespec_compare(&zone_mtime, &mtime) == 0) {
242d83a80eeSchristos VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
243d83a80eeSchristos fname));
244d83a80eeSchristos return;
245d83a80eeSchristos }
246d83a80eeSchristos }
247ee758998Schristos if(ixfr_create_from_difference(zone, fname,
248ee758998Schristos &ixfr_create_already_done)) {
249ee758998Schristos ixfrcr = ixfr_create_start(zone, fname,
250ee758998Schristos zone->opts->pattern->ixfr_size, 0);
251ee758998Schristos if(!ixfrcr) {
252ee758998Schristos /* leaves the ixfrcr at NULL, so it is not created */
253ee758998Schristos log_msg(LOG_ERR, "out of memory starting ixfr create");
254ee758998Schristos }
255ee758998Schristos }
256d83a80eeSchristos
257d83a80eeSchristos assert(parser);
258d83a80eeSchristos /* wipe zone from memory */
259d83a80eeSchristos #ifdef NSEC3
260d83a80eeSchristos nsec3_clear_precompile(nsd->db, zone);
261d83a80eeSchristos zone->nsec3_param = NULL;
262a1620025Sprlw1 #endif
263a1620025Sprlw1 delete_zone_rrs(nsd->db, zone);
264d83a80eeSchristos errors = zonec_read(zone->opts->name, fname, zone);
265d83a80eeSchristos if(errors > 0) {
266d83a80eeSchristos log_msg(LOG_ERR, "zone %s file %s read with %u errors",
267d83a80eeSchristos zone->opts->name, fname, errors);
268d83a80eeSchristos /* wipe (partial) zone from memory */
269d83a80eeSchristos zone->is_ok = 1;
270d83a80eeSchristos #ifdef NSEC3
271d83a80eeSchristos nsec3_clear_precompile(nsd->db, zone);
272d83a80eeSchristos zone->nsec3_param = NULL;
273a1620025Sprlw1 #endif
274a1620025Sprlw1 delete_zone_rrs(nsd->db, zone);
275d83a80eeSchristos if(zone->filename)
276d83a80eeSchristos region_recycle(nsd->db->region, zone->filename,
277d83a80eeSchristos strlen(zone->filename)+1);
278d83a80eeSchristos zone->filename = NULL;
279d83a80eeSchristos if(zone->logstr)
280d83a80eeSchristos region_recycle(nsd->db->region, zone->logstr,
281d83a80eeSchristos strlen(zone->logstr)+1);
282d83a80eeSchristos zone->logstr = NULL;
283d83a80eeSchristos } else {
284d83a80eeSchristos VERBOSITY(1, (LOG_INFO, "zone %s read with success",
285d83a80eeSchristos zone->opts->name));
286d83a80eeSchristos zone->is_ok = 1;
287d83a80eeSchristos zone->is_changed = 0;
288d83a80eeSchristos /* store zone into udb */
289d83a80eeSchristos zone->mtime = mtime;
290d83a80eeSchristos if(zone->filename)
291d83a80eeSchristos region_recycle(nsd->db->region, zone->filename,
292d83a80eeSchristos strlen(zone->filename)+1);
293d83a80eeSchristos zone->filename = region_strdup(nsd->db->region, fname);
294d83a80eeSchristos if(zone->logstr)
295d83a80eeSchristos region_recycle(nsd->db->region, zone->logstr,
296d83a80eeSchristos strlen(zone->logstr)+1);
297d83a80eeSchristos zone->logstr = NULL;
298ee758998Schristos if(ixfr_create_already_done) {
299ee758998Schristos ixfr_readup_exist(zone, nsd, fname);
300ee758998Schristos } else if(ixfrcr) {
301ee758998Schristos if(!ixfr_create_perform(ixfrcr, zone, 1, nsd, fname,
302ee758998Schristos zone->opts->pattern->ixfr_number)) {
303ee758998Schristos log_msg(LOG_ERR, "failed to create IXFR");
304ee758998Schristos } else {
305ee758998Schristos VERBOSITY(2, (LOG_INFO, "zone %s created IXFR %s.ixfr",
306ee758998Schristos zone->opts->name, fname));
307ee758998Schristos }
308ee758998Schristos ixfr_create_free(ixfrcr);
309ee758998Schristos } else if(zone_is_ixfr_enabled(zone)) {
310ee758998Schristos ixfr_read_from_file(nsd, zone, fname);
311ee758998Schristos }
312d83a80eeSchristos }
313d83a80eeSchristos if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
314d83a80eeSchristos #ifdef NSEC3
315d83a80eeSchristos prehash_zone_complete(nsd->db, zone);
316d83a80eeSchristos #endif
317d83a80eeSchristos }
318d83a80eeSchristos
namedb_check_zonefile(struct nsd * nsd,udb_base * taskudb,udb_ptr * last_task,struct zone_options * zopt)319d83a80eeSchristos void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb,
3203fb62404Schristos udb_ptr* last_task, struct zone_options* zopt)
321d83a80eeSchristos {
322d83a80eeSchristos zone_type* zone;
323d83a80eeSchristos const dname_type* dname = (const dname_type*)zopt->node.key;
324d83a80eeSchristos /* find zone to go with it, or create it */
325d83a80eeSchristos zone = namedb_find_zone(nsd->db, dname);
326d83a80eeSchristos if(!zone) {
327d83a80eeSchristos zone = namedb_zone_create(nsd->db, dname, zopt);
328d83a80eeSchristos }
329d83a80eeSchristos namedb_read_zonefile(nsd, zone, taskudb, last_task);
330d83a80eeSchristos }
331d83a80eeSchristos
namedb_check_zonefiles(struct nsd * nsd,struct nsd_options * opt,udb_base * taskudb,udb_ptr * last_task)3323fb62404Schristos void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt,
333d83a80eeSchristos udb_base* taskudb, udb_ptr* last_task)
334d83a80eeSchristos {
3353fb62404Schristos struct zone_options* zo;
336d83a80eeSchristos /* check all zones in opt, create if not exist in main db */
3373fb62404Schristos RBTREE_FOR(zo, struct zone_options*, opt->zone_options) {
338d83a80eeSchristos namedb_check_zonefile(nsd, taskudb, last_task, zo);
339d83a80eeSchristos if(nsd->signal_hint_shutdown) break;
340d83a80eeSchristos }
341d83a80eeSchristos }
342