xref: /openbsd-src/usr.sbin/nsd/dbaccess.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*
2  * dbaccess.c -- access methods for nsd(8) database
3  *
4  * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <stdio.h>		/* DEBUG */
21 
22 #include "dns.h"
23 #include "namedb.h"
24 #include "util.h"
25 #include "options.h"
26 
27 int
28 namedb_lookup(struct namedb    *db,
29 	      const dname_type *dname,
30 	      domain_type     **closest_match,
31 	      domain_type     **closest_encloser)
32 {
33 	return domain_table_search(
34 		db->domains, dname, closest_match, closest_encloser);
35 }
36 
37 static int
38 read_magic(namedb_type *db)
39 {
40 	char buf[NAMEDB_MAGIC_SIZE];
41 
42 	if (fread(buf, sizeof(char), sizeof(buf), db->fd) != sizeof(buf))
43 		return 0;
44 
45 	return memcmp(buf, NAMEDB_MAGIC, NAMEDB_MAGIC_SIZE) == 0;
46 }
47 
48 static const dname_type *
49 read_dname(FILE *fd, region_type *region)
50 {
51 	uint8_t size;
52 	uint8_t temp[MAXDOMAINLEN];
53 
54 	if (fread(&size, sizeof(uint8_t), 1, fd) != 1)
55 		return NULL;
56 	if (fread(temp, sizeof(uint8_t), size, fd) != size)
57 		return NULL;
58 
59 	return dname_make(region, temp, 1);
60 }
61 
62 static int
63 read_size(namedb_type *db, uint32_t *result)
64 {
65 	if (fread(result, sizeof(*result), 1, db->fd) == 1) {
66 		*result = ntohl(*result);
67 		return 1;
68 	} else {
69 		return 0;
70 	}
71 }
72 
73 static domain_type *
74 read_domain(namedb_type *db, uint32_t domain_count, domain_type **domains)
75 {
76 	uint32_t domain_number;
77 
78 	if (!read_size(db, &domain_number))
79 		return NULL;
80 
81 	if (domain_number == 0 || domain_number > domain_count)
82 		return NULL;
83 
84 	return domains[domain_number - 1];
85 }
86 
87 static zone_type *
88 read_zone(namedb_type *db, uint32_t zone_count, zone_type **zones)
89 {
90 	uint32_t zone_number;
91 
92 	if (!read_size(db, &zone_number))
93 		return NULL;
94 
95 	if (zone_number == 0 || zone_number > zone_count)
96 		return NULL;
97 
98 	return zones[zone_number - 1];
99 }
100 
101 static int
102 read_rdata_atom(namedb_type *db, uint16_t type, int index, uint32_t domain_count, domain_type **domains, rdata_atom_type *result)
103 {
104 	uint8_t data[65536];
105 
106 	if (rdata_atom_is_domain(type, index)) {
107 		result->domain = read_domain(db, domain_count, domains);
108 		if (!result->domain)
109 			return 0;
110 	} else {
111 		uint16_t size;
112 
113 		if (fread(&size, sizeof(size), 1, db->fd) != 1)
114 			return 0;
115 		size = ntohs(size);
116 		if (fread(data, sizeof(uint8_t), size, db->fd) != size)
117 			return 0;
118 
119 		result->data = (uint16_t *) region_alloc(
120 			db->region, sizeof(uint16_t) + size);
121 		memcpy(result->data, &size, sizeof(uint16_t));
122 		memcpy((uint8_t *) result->data + sizeof(uint16_t), data, size);
123 	}
124 
125 	return 1;
126 }
127 
128 static rrset_type *
129 read_rrset(namedb_type *db,
130 	   uint32_t domain_count, domain_type **domains,
131 	   uint32_t zone_count, zone_type **zones)
132 {
133 	rrset_type *rrset;
134 	int i, j;
135 	domain_type *owner;
136 	uint16_t type;
137 	uint16_t klass;
138 	uint32_t soa_minimum;
139 
140 	owner = read_domain(db, domain_count, domains);
141 	if (!owner)
142 		return NULL;
143 
144 	rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type));
145 
146 	rrset->zone = read_zone(db, zone_count, zones);
147 	if (!rrset->zone)
148 		return NULL;
149 
150 	if (fread(&type, sizeof(type), 1, db->fd) != 1)
151 		return NULL;
152 	type = ntohs(type);
153 
154 	if (fread(&klass, sizeof(klass), 1, db->fd) != 1)
155 		return NULL;
156 	klass = ntohs(klass);
157 
158 	if (fread(&rrset->rr_count, sizeof(rrset->rr_count), 1, db->fd) != 1)
159 		return NULL;
160 	rrset->rr_count = ntohs(rrset->rr_count);
161 	rrset->rrs = (rr_type *) region_alloc(
162 		db->region, rrset->rr_count * sizeof(rr_type));
163 
164 	assert(rrset->rr_count > 0);
165 
166 	for (i = 0; i < rrset->rr_count; ++i) {
167 		rr_type *rr = &rrset->rrs[i];
168 
169 		rr->owner = owner;
170 		rr->type = type;
171 		rr->klass = klass;
172 
173 		if (fread(&rr->rdata_count, sizeof(rr->rdata_count), 1, db->fd) != 1)
174 			return NULL;
175 		rr->rdata_count = ntohs(rr->rdata_count);
176 		rr->rdatas = (rdata_atom_type *) region_alloc(
177 			db->region, rr->rdata_count * sizeof(rdata_atom_type));
178 
179 		if (fread(&rr->ttl, sizeof(rr->ttl), 1, db->fd) != 1)
180 			return NULL;
181 		rr->ttl = ntohl(rr->ttl);
182 
183 		for (j = 0; j < rr->rdata_count; ++j) {
184 			if (!read_rdata_atom(db, rr->type, j, domain_count, domains, &rr->rdatas[j]))
185 				return NULL;
186 		}
187 	}
188 
189 	domain_add_rrset(owner, rrset);
190 
191 	if (rrset_rrtype(rrset) == TYPE_SOA) {
192 		assert(owner == rrset->zone->apex);
193 		rrset->zone->soa_rrset = rrset;
194 
195 		/* BUG #103 add another soa with a tweaked ttl */
196 		rrset->zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type));
197 		rrset->zone->soa_nx_rrset->rrs =
198 			region_alloc(db->region, rrset->rr_count * sizeof(rr_type));
199 
200 		memcpy(rrset->zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type));
201 		rrset->zone->soa_nx_rrset->rr_count = 1;
202 		rrset->zone->soa_nx_rrset->next = 0;
203 
204 		/* also add a link to the zone */
205 		rrset->zone->soa_nx_rrset->zone = rrset->zone;
206 
207 		/* check the ttl and MINIMUM value and set accordinly */
208 		memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]),
209 				rdata_atom_size(rrset->rrs->rdatas[6]));
210 		if (rrset->rrs->ttl > ntohl(soa_minimum)) {
211 			rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum);
212 		}
213 		owner->has_SOA = 1;
214 
215 	} else if (owner == rrset->zone->apex
216 		   && rrset_rrtype(rrset) == TYPE_NS)
217 	{
218 		rrset->zone->ns_rrset = rrset;
219 	}
220 #ifdef NSEC3
221 #ifndef FULL_PREHASH
222 	else if (type == TYPE_NSEC3) {
223 		if (0 != namedb_add_nsec3_domain(db, owner, rrset->zone)) {
224 			return NULL;
225 		}
226 	}
227 #endif /* !FULL_PREHASH */
228 #endif /* NSEC3 */
229 	if (rrset_rrtype(rrset) == TYPE_RRSIG && owner == rrset->zone->apex) {
230 		for (i = 0; i < rrset->rr_count; ++i) {
231 			if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) {
232 				rrset->zone->is_secure = 1;
233 				break;
234 			}
235 		}
236 	}
237 	return rrset;
238 }
239 
240 struct namedb *
241 namedb_open (const char *filename, nsd_options_t* opt, size_t num_children)
242 {
243 	namedb_type *db;
244 
245 	/*
246 	 * Temporary region used while loading domain names from the
247 	 * database.  The region is freed after each time a dname is
248 	 * read from the database.
249 	 */
250 	region_type *dname_region;
251 
252 	/*
253 	 * Temporary region used to store array of domains and zones
254 	 * while loading the database.  The region is freed before
255 	 * returning.
256 	 */
257 	region_type *temp_region;
258 
259 	uint32_t dname_count;
260 	domain_type **domains;	/* Indexed by domain number.  */
261 
262 	uint32_t zone_count;
263 	zone_type **zones;	/* Indexed by zone number.  */
264 
265 	uint32_t i;
266 	uint32_t rrset_count = 0;
267 	uint32_t rr_count = 0;
268 
269 	rrset_type *rrset;
270 
271 	DEBUG(DEBUG_DBACCESS, 2,
272 	      (LOG_INFO, "sizeof(namedb_type) = %lu\n", (unsigned long) sizeof(namedb_type)));
273 	DEBUG(DEBUG_DBACCESS, 2,
274 	      (LOG_INFO, "sizeof(zone_type) = %lu\n", (unsigned long) sizeof(zone_type)));
275 	DEBUG(DEBUG_DBACCESS, 2,
276 	      (LOG_INFO, "sizeof(domain_type) = %lu\n", (unsigned long) sizeof(domain_type)));
277 	DEBUG(DEBUG_DBACCESS, 2,
278 	      (LOG_INFO, "sizeof(rrset_type) = %lu\n", (unsigned long) sizeof(rrset_type)));
279 	DEBUG(DEBUG_DBACCESS, 2,
280 	      (LOG_INFO, "sizeof(rr_type) = %lu\n", (unsigned long) sizeof(rr_type)));
281 	DEBUG(DEBUG_DBACCESS, 2,
282 	      (LOG_INFO, "sizeof(rdata_atom_type) = %lu\n", (unsigned long) sizeof(rdata_atom_type)));
283 	DEBUG(DEBUG_DBACCESS, 2,
284 	      (LOG_INFO, "sizeof(rbnode_t) = %lu\n", (unsigned long) sizeof(rbnode_t)));
285 
286 	if ((db = namedb_create()) == NULL) {
287 		log_msg(LOG_ERR,
288 			"insufficient memory to create database");
289 		return NULL;
290 	}
291  	db->filename = region_strdup(db->region, filename);
292 
293 	if (gettimeofday(&(db->diff_timestamp), NULL) != 0) {
294 		log_msg(LOG_ERR, "unable to load %s: cannot initialize"
295 				 "timestamp", db->filename);
296 		namedb_destroy(db);
297 		return NULL;
298 	}
299 
300 	/* Open it... */
301 	db->fd = fopen(db->filename, "r");
302 	if (db->fd == NULL) {
303 		log_msg(LOG_ERR, "unable to load %s: %s",
304 			db->filename, strerror(errno));
305 		namedb_destroy(db);
306 		return NULL;
307 	}
308 
309 	if (!read_magic(db)) {
310 		log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename);
311 		log_msg(LOG_ERR, "cannot load database, incompatible version "
312 					"number. Please rebuild database and "
313                                         "start again.");
314 		namedb_close(db);
315 		return NULL;
316 	}
317 
318 	if (!read_size(db, &zone_count)) {
319 		log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename);
320 		namedb_close(db);
321 		return NULL;
322 	}
323 
324 	DEBUG(DEBUG_DBACCESS, 1,
325 	      (LOG_INFO, "Retrieving %lu zones\n", (unsigned long) zone_count));
326 
327 	temp_region = region_create(xalloc, free);
328 	dname_region = region_create(xalloc, free);
329 
330 	db->zone_count = zone_count;
331 	zones = (zone_type **) region_alloc(temp_region,
332 					    zone_count * sizeof(zone_type *));
333 	for (i = 0; i < zone_count; ++i) {
334 		const dname_type *dname = read_dname(db->fd, dname_region);
335 		if (!dname) {
336 			log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename);
337 			region_destroy(dname_region);
338 			region_destroy(temp_region);
339 			namedb_close(db);
340 			return NULL;
341 		}
342 		zones[i] = (zone_type *) region_alloc(db->region,
343 						      sizeof(zone_type));
344 		zones[i]->next = db->zones;
345 		db->zones = zones[i];
346 		zones[i]->apex = domain_table_insert(db->domains, dname);
347 		zones[i]->soa_rrset = NULL;
348 		zones[i]->soa_nx_rrset = NULL;
349 		zones[i]->ns_rrset = NULL;
350 #ifdef NSEC3
351 		zones[i]->nsec3_soa_rr = NULL;
352 		zones[i]->nsec3_last = NULL;
353 #endif
354 		zones[i]->opts = zone_options_find(opt, domain_dname(zones[i]->apex));
355 		zones[i]->number = i + 1;
356 		zones[i]->is_secure = 0;
357 		zones[i]->updated = 1;
358 		zones[i]->is_ok = 0;
359 		zones[i]->dirty = region_alloc(db->region, sizeof(uint8_t)*num_children);
360 		memset(zones[i]->dirty, 0, sizeof(uint8_t)*num_children);
361 		if(!zones[i]->opts) {
362 			log_msg(LOG_ERR, "cannot load database. Zone %s in db "
363 					 "%s, but not in config file (might "
364 					 "happen if you edited the config "
365 					 "file). Please rebuild database and "
366 					 "start again.",
367 				dname_to_string(dname, NULL), db->filename);
368 			region_destroy(dname_region);
369 			region_destroy(temp_region);
370 			namedb_close(db);
371 			return NULL;
372 		}
373 #ifdef NSEC3
374 #ifndef FULL_PREHASH
375 		zones[i]->nsec3_domains = NULL;
376 		if (0 != zone_nsec3_domains_create(db, zones[i])) {
377 			log_msg(LOG_ERR,
378 				"insufficient memory for NSEC3 tree, "
379 				"unable to read database");
380 			region_destroy(dname_region);
381 			region_destroy(temp_region);
382 			namedb_close(db);
383 			return NULL;
384 		}
385 #endif /* !FULL_PREHASH */
386 #endif /* NSEC3 */
387 		region_free_all(dname_region);
388 	}
389 
390 	if (!read_size(db, &dname_count)) {
391 		log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename);
392 		region_destroy(dname_region);
393 		region_destroy(temp_region);
394 		namedb_close(db);
395 		return NULL;
396 	}
397 
398 	DEBUG(DEBUG_DBACCESS, 1,
399 	      (LOG_INFO, "Retrieving %lu domain names\n", (unsigned long) dname_count));
400 
401 	domains = (domain_type **) region_alloc(
402 		temp_region, dname_count * sizeof(domain_type *));
403 	for (i = 0; i < dname_count; ++i) {
404 		const dname_type *dname = read_dname(db->fd, dname_region);
405 		if (!dname) {
406 			log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename);
407 			region_destroy(dname_region);
408 			region_destroy(temp_region);
409 			namedb_close(db);
410 			return NULL;
411 		}
412 		domains[i] = domain_table_insert(db->domains, dname);
413 		region_free_all(dname_region);
414 	}
415 
416 	region_destroy(dname_region);
417 
418 #ifndef NDEBUG
419 	fprintf(stderr, "database region after loading domain names: ");
420 	region_dump_stats(db->region, stderr);
421 	fprintf(stderr, "\n");
422 #endif
423 
424 	while ((rrset = read_rrset(db, dname_count, domains, zone_count, zones))) {
425 		++rrset_count;
426 		rr_count += rrset->rr_count;
427 	}
428 
429 	DEBUG(DEBUG_DBACCESS, 1,
430 	      (LOG_INFO, "Retrieved %lu RRs in %lu RRsets\n",
431 	       (unsigned long) rr_count, (unsigned long) rrset_count));
432 
433 	region_destroy(temp_region);
434 
435 	if ((db->crc_pos = ftello(db->fd)) == -1) {
436 		log_msg(LOG_ERR, "ftello %s failed: %s",
437 			db->filename, strerror(errno));
438 		namedb_close(db);
439 		return NULL;
440 	}
441 	if (!read_size(db, &db->crc)) {
442 		log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename);
443 		namedb_close(db);
444 		return NULL;
445 	}
446 	if (!read_magic(db)) {
447 		log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename);
448 		log_msg(LOG_ERR, "cannot load database, incompatible version "
449 					"number. Please rebuild database and "
450                                         "start again.");
451 		namedb_close(db);
452 		return NULL;
453 	}
454 
455 	fclose(db->fd);
456 	db->fd = NULL;
457 
458 #ifndef NDEBUG
459 	fprintf(stderr, "database region after loading database: ");
460 	region_dump_stats(db->region, stderr);
461 	fprintf(stderr, "\n");
462 #endif
463 
464 	return db;
465 }
466 
467 void
468 namedb_close (struct namedb *db)
469 {
470 	namedb_fd_close(db);
471 	if (db) {
472 		namedb_destroy(db);
473 	}
474 }
475 
476 void
477 namedb_fd_close (struct namedb *db)
478 {
479 	if (db && db->fd) {
480 		fclose(db->fd);
481 	}
482 }
483 
484