xref: /minix3/external/bsd/bind/dist/lib/dns/tests/rbt_serialize_test.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1 /*	$NetBSD: rbt_serialize_test.c,v 1.1.1.4 2015/07/08 15:38:04 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id: rbt_test.c,v 1.1.14.8 2012/02/10 16:24:37 ckb Exp  */
20 
21 /* ! \file */
22 
23 #include <config.h>
24 #include <atf-c.h>
25 #include <isc/mem.h>
26 #include <isc/random.h>
27 #include <isc/string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <sys/mman.h>
31 
32 #ifdef HAVE_INTTYPES_H
33 #include <inttypes.h> /* uintptr_t */
34 #endif
35 
36 #include <dns/rbt.h>
37 #include <dns/fixedname.h>
38 #include <dns/result.h>
39 #include <dns/compress.h>
40 #include "dnstest.h"
41 
42 #include <isc/app.h>
43 #include <isc/buffer.h>
44 #include <isc/entropy.h>
45 #include <isc/file.h>
46 #include <isc/hash.h>
47 #include <isc/mem.h>
48 #include <isc/os.h>
49 #include <isc/string.h>
50 #include <isc/socket.h>
51 #include <isc/stdio.h>
52 #include <isc/task.h>
53 #include <isc/timer.h>
54 #include <isc/util.h>
55 
56 #include <dns/log.h>
57 #include <dns/name.h>
58 #include <dns/result.h>
59 
60 #include <dst/dst.h>
61 
62 #ifndef MAP_FILE
63 #define MAP_FILE 0
64 #endif
65 
66 typedef struct data_holder {
67 	int len;
68 	const char *data;
69 } data_holder_t;
70 
71 typedef struct rbt_testdata {
72 	const char *name;
73 	size_t name_len;
74 	data_holder_t data;
75 } rbt_testdata_t;
76 
77 #define DATA_ITEM(name) { (name), sizeof(name) - 1, { sizeof(name), (name) } }
78 
79 rbt_testdata_t testdata[] = {
80 	DATA_ITEM("first.com."),
81 	DATA_ITEM("one.net."),
82 	DATA_ITEM("two.com."),
83 	DATA_ITEM("three.org."),
84 	DATA_ITEM("asdf.com."),
85 	DATA_ITEM("ghjkl.com."),
86 	DATA_ITEM("1.edu."),
87 	DATA_ITEM("2.edu."),
88 	DATA_ITEM("3.edu."),
89 	DATA_ITEM("123.edu."),
90 	DATA_ITEM("1236.com."),
91 	DATA_ITEM("and_so_forth.com."),
92 	DATA_ITEM("thisisalongname.com."),
93 	DATA_ITEM("a.b."),
94 	DATA_ITEM("test.net."),
95 	DATA_ITEM("whoknows.org."),
96 	DATA_ITEM("blargh.com."),
97 	DATA_ITEM("www.joe.com."),
98 	DATA_ITEM("test.com."),
99 	DATA_ITEM("isc.org."),
100 	DATA_ITEM("uiop.mil."),
101 	DATA_ITEM("last.fm."),
102 	{ NULL, 0, { 0, NULL } }
103 };
104 
105 static void
delete_data(void * data,void * arg)106 delete_data(void *data, void *arg) {
107 	UNUSED(arg);
108 	UNUSED(data);
109 }
110 
111 static isc_result_t
write_data(FILE * file,unsigned char * datap,void * arg,isc_uint64_t * crc)112 write_data(FILE *file, unsigned char *datap, void *arg, isc_uint64_t *crc) {
113 	isc_result_t result;
114 	size_t ret = 0;
115 	data_holder_t *data = (data_holder_t *)datap;
116 	data_holder_t temp;
117 	off_t where;
118 
119 	UNUSED(arg);
120 
121 	REQUIRE(file != NULL);
122 	REQUIRE(crc != NULL);
123 	REQUIRE(data != NULL);
124 	REQUIRE((data->len == 0 && data->data == NULL) ||
125 		(data->len != 0 && data->data != NULL));
126 
127 	result = isc_stdio_tell(file, &where);
128 	if (result != ISC_R_SUCCESS)
129 		return (result);
130 
131 	temp = *data;
132 	temp.data = (data->len == 0
133 		     ? NULL
134 		     : (char *)((uintptr_t)where + sizeof(data_holder_t)));
135 
136 	isc_crc64_update(crc, (void *)&temp, sizeof(temp));
137 	ret = fwrite(&temp, sizeof(data_holder_t), 1, file);
138 	if (ret != 1)
139 		return (ISC_R_FAILURE);
140 	if (data->len > 0) {
141 		isc_crc64_update(crc, (const void *)data->data, data->len);
142 		ret = fwrite(data->data, data->len, 1, file);
143 		if (ret != 1)
144 			return (ISC_R_FAILURE);
145 	}
146 
147 	return (ISC_R_SUCCESS);
148 }
149 
150 static isc_result_t
fix_data(dns_rbtnode_t * p,void * base,size_t max,void * arg,isc_uint64_t * crc)151 fix_data(dns_rbtnode_t *p, void *base, size_t max, void *arg,
152 	 isc_uint64_t *crc)
153 {
154 	data_holder_t *data = p->data;
155 	size_t size;
156 
157 	UNUSED(base);
158 	UNUSED(max);
159 	UNUSED(arg);
160 
161 	REQUIRE(crc != NULL);
162 	REQUIRE(p != NULL);
163 
164 
165 	if (data == NULL)
166 		printf("fixing data: data NULL\n");
167 	else
168 		printf("fixing data: len %d, data %p\n", data->len, data->data);
169 
170 	if (data == NULL ||
171 	    (data->len == 0 && data->data != NULL) ||
172 	    (data->len != 0 && data->data == NULL))
173 		return (ISC_R_INVALIDFILE);
174 
175 	size = max - ((char *)p - (char *)base);
176 
177 	if (data->len > (int) size || data->data > (const char *) max) {
178 		printf("data invalid\n");
179 		return (ISC_R_INVALIDFILE);
180 	}
181 
182 	isc_crc64_update(crc, (void *)data, sizeof(*data));
183 
184 	data->data = (data->len == 0)
185 		? NULL
186 		: (char *)data + sizeof(data_holder_t);
187 
188 	if (data->len > 0)
189 		isc_crc64_update(crc, (const void *)data->data, data->len);
190 
191 	return (ISC_R_SUCCESS);
192 }
193 
194 /*
195  * Load test data into the RBT.
196  */
197 static void
add_test_data(isc_mem_t * mymctx,dns_rbt_t * rbt)198 add_test_data(isc_mem_t *mymctx, dns_rbt_t *rbt) {
199 	char buffer[1024];
200 	isc_buffer_t b;
201 	isc_result_t result;
202 	dns_fixedname_t fname;
203 	dns_name_t *name;
204 	dns_compress_t cctx;
205 	rbt_testdata_t *testdatap = testdata;
206 
207 	dns_compress_init(&cctx, -1, mymctx);
208 
209 	while (testdatap->name != NULL && testdatap->data.data != NULL) {
210 		memmove(buffer, testdatap->name, testdatap->name_len);
211 
212 		isc_buffer_init(&b, buffer, testdatap->name_len);
213 		isc_buffer_add(&b, testdatap->name_len);
214 		dns_fixedname_init(&fname);
215 		name = dns_fixedname_name(&fname);
216 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
217 		if (result != ISC_R_SUCCESS) {
218 			testdatap++;
219 			continue;
220 		}
221 
222 		if (name != NULL) {
223 			result = dns_rbt_addname(rbt, name, &testdatap->data);
224 			ATF_CHECK_STREQ(dns_result_totext(result), "success");
225 		}
226 		testdatap++;
227 	}
228 
229 	dns_compress_invalidate(&cctx);
230 }
231 
232 /*
233  * Walk the tree and ensure that all the test nodes are present.
234  */
235 static void
check_test_data(dns_rbt_t * rbt)236 check_test_data(dns_rbt_t *rbt) {
237 	char buffer[1024];
238 	char *arg;
239 	dns_fixedname_t fname;
240 	dns_fixedname_t fixed;
241 	dns_name_t *name;
242 	isc_buffer_t b;
243 	data_holder_t *data;
244 	isc_result_t result;
245 	dns_name_t *foundname;
246 	rbt_testdata_t *testdatap = testdata;
247 
248 	dns_fixedname_init(&fixed);
249 	foundname = dns_fixedname_name(&fixed);
250 
251 	while (testdatap->name != NULL && testdatap->data.data != NULL) {
252 		memmove(buffer, testdatap->name, testdatap->name_len + 1);
253 		arg = buffer;
254 
255 		isc_buffer_init(&b, arg, testdatap->name_len);
256 		isc_buffer_add(&b, testdatap->name_len);
257 		dns_fixedname_init(&fname);
258 		name = dns_fixedname_name(&fname);
259 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
260 		if (result != ISC_R_SUCCESS) {
261 			testdatap++;
262 			continue;
263 		}
264 
265 		data = NULL;
266 		result = dns_rbt_findname(rbt, name, 0, foundname,
267 					  (void *) &data);
268 		ATF_CHECK_STREQ(dns_result_totext(result), "success");
269 
270 		testdatap++;
271 	}
272 }
273 
274 static void
data_printer(FILE * out,void * datap)275 data_printer(FILE *out, void *datap)
276 {
277 	data_holder_t *data = (data_holder_t *)datap;
278 
279 	fprintf(out, "%d bytes, %s", data->len, data->data);
280 }
281 
282 ATF_TC(serialize);
ATF_TC_HEAD(serialize,tc)283 ATF_TC_HEAD(serialize, tc) {
284 	atf_tc_set_md_var(tc, "descr", "Test writing an rbt to file");
285 }
ATF_TC_BODY(serialize,tc)286 ATF_TC_BODY(serialize, tc) {
287 	dns_rbt_t *rbt = NULL;
288 	isc_result_t result;
289 	FILE *rbtfile = NULL;
290 	dns_rbt_t *rbt_deserialized = NULL;
291 	off_t offset;
292 	int fd;
293 	off_t filesize = 0;
294 	char *base;
295 
296 	UNUSED(tc);
297 
298 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
299 
300 	result = dns_test_begin(NULL, ISC_TRUE);
301 	ATF_CHECK_STREQ(dns_result_totext(result), "success");
302 	result = dns_rbt_create(mctx, delete_data, NULL, &rbt);
303 	ATF_CHECK_STREQ(dns_result_totext(result), "success");
304 
305 	add_test_data(mctx, rbt);
306 
307 	dns_rbt_printtext(rbt, data_printer, stdout);
308 
309 	/*
310 	 * Serialize the tree.
311 	 */
312 	printf("serialization begins.\n");
313 	rbtfile = fopen("./zone.bin", "w+b");
314 	ATF_REQUIRE(rbtfile != NULL);
315 	result = dns_rbt_serialize_tree(rbtfile, rbt, write_data, NULL,
316 					&offset);
317 	ATF_REQUIRE(result == ISC_R_SUCCESS);
318 	dns_rbt_destroy(&rbt);
319 
320 	/*
321 	 * Deserialize the tree
322 	 */
323 	printf("deserialization begins.\n");
324 
325 	/*
326 	 * Map in the whole file in one go
327 	 */
328 	fd = open("zone.bin", O_RDWR);
329 	isc_file_getsizefd(fd, &filesize);
330 	base = mmap(NULL, filesize,
331 		    PROT_READ|PROT_WRITE,
332 		    MAP_FILE|MAP_PRIVATE, fd, 0);
333 	ATF_REQUIRE(base != NULL && base != MAP_FAILED);
334 	close(fd);
335 
336 	result = dns_rbt_deserialize_tree(base, filesize, 0, mctx,
337 					  delete_data, NULL, fix_data, NULL,
338 					  NULL, &rbt_deserialized);
339 
340 	/* Test to make sure we have a valid tree */
341 	ATF_REQUIRE(result == ISC_R_SUCCESS);
342 	if (rbt_deserialized == NULL)
343 		atf_tc_fail("deserialized rbt is null!"); /* Abort execution. */
344 
345 	check_test_data(rbt_deserialized);
346 
347 	dns_rbt_printtext(rbt_deserialized, data_printer, stdout);
348 
349 	dns_rbt_destroy(&rbt_deserialized);
350 	munmap(base, filesize);
351 	unlink("zone.bin");
352 	dns_test_end();
353 }
354 
355 ATF_TC(deserialize_corrupt);
ATF_TC_HEAD(deserialize_corrupt,tc)356 ATF_TC_HEAD(deserialize_corrupt, tc) {
357 	atf_tc_set_md_var(tc, "descr", "Test reading a corrupt map file");
358 }
ATF_TC_BODY(deserialize_corrupt,tc)359 ATF_TC_BODY(deserialize_corrupt, tc) {
360 	dns_rbt_t *rbt = NULL;
361 	isc_result_t result;
362 	FILE *rbtfile = NULL;
363 	off_t offset;
364 	int fd;
365 	off_t filesize = 0;
366 	char *base, *p, *q;
367 	isc_uint32_t r;
368 	int i;
369 
370 	UNUSED(tc);
371 
372 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
373 
374 	result = dns_test_begin(NULL, ISC_TRUE);
375 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
376 
377 	/* Set up map file */
378 	result = dns_rbt_create(mctx, delete_data, NULL, &rbt);
379 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
380 
381 	add_test_data(mctx, rbt);
382 	rbtfile = fopen("./zone.bin", "w+b");
383 	ATF_REQUIRE(rbtfile != NULL);
384 	result = dns_rbt_serialize_tree(rbtfile, rbt, write_data, NULL,
385 					&offset);
386 	ATF_REQUIRE(result == ISC_R_SUCCESS);
387 	dns_rbt_destroy(&rbt);
388 
389 	/* Read back with random fuzzing */
390 	for (i = 0; i < 256; i++) {
391 		dns_rbt_t *rbt_deserialized = NULL;
392 
393 		fd = open("zone.bin", O_RDWR);
394 		isc_file_getsizefd(fd, &filesize);
395 		base = mmap(NULL, filesize,
396 			    PROT_READ|PROT_WRITE,
397 			    MAP_FILE|MAP_PRIVATE, fd, 0);
398 		ATF_REQUIRE(base != NULL && base != MAP_FAILED);
399 		close(fd);
400 
401 		/* Randomly fuzz a portion of the memory */
402 		isc_random_get(&r);
403 		p = base + (r % filesize);
404 		q = base + filesize;
405 		isc_random_get(&r);
406 		q -= (r % (q - p));
407 		while (p++ < q) {
408 			isc_random_get(&r);
409 			*p = r & 0xff;
410 		}
411 
412 		result = dns_rbt_deserialize_tree(base, filesize, 0, mctx,
413 						  delete_data, NULL,
414 						  fix_data, NULL,
415 						  NULL, &rbt_deserialized);
416 		printf("%d: %s\n", i, isc_result_totext(result));
417 
418 		/* Test to make sure we have a valid tree */
419 		ATF_REQUIRE(result == ISC_R_SUCCESS ||
420 			    result == ISC_R_INVALIDFILE);
421 		if (result != ISC_R_SUCCESS)
422 			ATF_REQUIRE(rbt_deserialized == NULL);
423 
424 		if (rbt_deserialized != NULL)
425 			dns_rbt_destroy(&rbt_deserialized);
426 
427 		munmap(base, filesize);
428 	}
429 
430 	unlink("zone.bin");
431 	dns_test_end();
432 }
433 
434 
435 ATF_TC(serialize_align);
ATF_TC_HEAD(serialize_align,tc)436 ATF_TC_HEAD(serialize_align, tc) {
437 	atf_tc_set_md_var(tc, "descr",
438 			  "Test the dns_rbt_serialize_align() function.");
439 }
ATF_TC_BODY(serialize_align,tc)440 ATF_TC_BODY(serialize_align, tc) {
441 	UNUSED(tc);
442 
443 	ATF_CHECK(dns_rbt_serialize_align(0) == 0);
444 	ATF_CHECK(dns_rbt_serialize_align(1) == 8);
445 	ATF_CHECK(dns_rbt_serialize_align(2) == 8);
446 	ATF_CHECK(dns_rbt_serialize_align(3) == 8);
447 	ATF_CHECK(dns_rbt_serialize_align(4) == 8);
448 	ATF_CHECK(dns_rbt_serialize_align(5) == 8);
449 	ATF_CHECK(dns_rbt_serialize_align(6) == 8);
450 	ATF_CHECK(dns_rbt_serialize_align(7) == 8);
451 	ATF_CHECK(dns_rbt_serialize_align(8) == 8);
452 	ATF_CHECK(dns_rbt_serialize_align(9) == 16);
453 	ATF_CHECK(dns_rbt_serialize_align(0xff) == 0x100);
454 	ATF_CHECK(dns_rbt_serialize_align(0x301) == 0x308);
455 }
456 
457 /*
458  * Main
459  */
ATF_TP_ADD_TCS(tp)460 ATF_TP_ADD_TCS(tp) {
461 	ATF_TP_ADD_TC(tp, serialize);
462 	ATF_TP_ADD_TC(tp, deserialize_corrupt);
463 	ATF_TP_ADD_TC(tp, serialize_align);
464 
465 	return (atf_no_error());
466 }
467