1/*	$NetBSD$	*/
2
3/*
4 * Copyright (C) 2011, 2012  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 */
20
21/*! \file */
22
23#include <config.h>
24
25#include <atf-c.h>
26
27#include <unistd.h>
28
29#include <dns/cache.h>
30#include <dns/callbacks.h>
31#include <dns/db.h>
32#include <dns/master.h>
33#include <dns/masterdump.h>
34#include <dns/name.h>
35#include <dns/rdata.h>
36#include <dns/rdatalist.h>
37#include <dns/rdataset.h>
38
39#include "dnstest.h"
40
41/*
42 * Helper functions
43 */
44
45#define	BUFLEN		255
46#define	BIGBUFLEN	(70 * 1024)
47#define TEST_ORIGIN	"test"
48
49static dns_masterrawheader_t header;
50static isc_boolean_t headerset;
51
52static isc_result_t
53add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset);
54
55static void
56rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *header);
57
58static isc_result_t
59add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset) {
60	char buf[BIGBUFLEN];
61	isc_buffer_t target;
62	isc_result_t result;
63
64	UNUSED(arg);
65
66	isc_buffer_init(&target, buf, BIGBUFLEN);
67	result = dns_rdataset_totext(dataset, owner, ISC_FALSE, ISC_FALSE,
68				     &target);
69	return(result);
70}
71
72static void
73rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *h) {
74	UNUSED(zone);
75	header = *h;
76	headerset = ISC_TRUE;
77}
78
79static int
80test_master(const char *testfile, dns_masterformat_t format) {
81	isc_result_t		result;
82	int			len;
83	char			origin[sizeof(TEST_ORIGIN)];
84	dns_name_t		dns_origin;
85	isc_buffer_t		source;
86	isc_buffer_t		target;
87	unsigned char		name_buf[BUFLEN];
88	dns_rdatacallbacks_t	callbacks;
89
90	strcpy(origin, TEST_ORIGIN);
91	len = strlen(origin);
92	isc_buffer_init(&source, origin, len);
93	isc_buffer_add(&source, len);
94	isc_buffer_setactive(&source, len);
95	isc_buffer_init(&target, name_buf, BUFLEN);
96	dns_name_init(&dns_origin, NULL);
97	dns_master_initrawheader(&header);
98
99	result = dns_name_fromtext(&dns_origin, &source, dns_rootname,
100				   0, &target);
101	if (result != ISC_R_SUCCESS)
102		return(result);
103
104	dns_rdatacallbacks_init_stdio(&callbacks);
105	callbacks.add = add_callback;
106	callbacks.rawdata = rawdata_callback;
107	callbacks.zone = NULL;
108	headerset = ISC_FALSE;
109	result = dns_master_loadfile2(testfile, &dns_origin, &dns_origin,
110				      dns_rdataclass_in, ISC_TRUE,
111				      &callbacks, mctx, format);
112	return (result);
113}
114
115/*
116 * Individual unit tests
117 */
118
119/* Successful load test */
120ATF_TC(load);
121ATF_TC_HEAD(load, tc) {
122	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() loads a "
123				       "valid master file and returns success");
124}
125ATF_TC_BODY(load, tc) {
126	isc_result_t result;
127
128	UNUSED(tc);
129
130	result = dns_test_begin(NULL, ISC_FALSE);
131	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
132
133	result = test_master("testdata/master/master1.data",
134			     dns_masterformat_text);
135	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
136
137	dns_test_end();
138}
139
140
141/* Unepxected end of file test */
142ATF_TC(unexpected);
143ATF_TC_HEAD(unexpected, tc) {
144	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
145				       "DNS_R_UNEXPECTED when file ends "
146				       "too soon");
147}
148ATF_TC_BODY(unexpected, tc) {
149	isc_result_t result;
150
151	UNUSED(tc);
152
153	result = dns_test_begin(NULL, ISC_FALSE);
154	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
155
156	result = test_master("testdata/master/master2.data",
157			     dns_masterformat_text);
158	ATF_REQUIRE_EQ(result, ISC_R_UNEXPECTEDEND);
159
160	dns_test_end();
161}
162
163
164/* No owner test */
165ATF_TC(noowner);
166ATF_TC_HEAD(noowner, tc) {
167	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() accepts broken "
168				       "zones with no TTL for first record "
169				       "if it is an SOA");
170}
171ATF_TC_BODY(noowner, tc) {
172	isc_result_t result;
173
174	UNUSED(tc);
175
176	result = dns_test_begin(NULL, ISC_FALSE);
177	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
178
179	result = test_master("testdata/master/master3.data",
180			     dns_masterformat_text);
181	ATF_REQUIRE_EQ(result, DNS_R_NOOWNER);
182
183	dns_test_end();
184}
185
186
187/* No TTL test */
188ATF_TC(nottl);
189ATF_TC_HEAD(nottl, tc) {
190	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
191				       "DNS_R_NOOWNER when no owner name "
192				       "is specified");
193}
194
195ATF_TC_BODY(nottl, tc) {
196	isc_result_t result;
197
198	UNUSED(tc);
199
200	result = dns_test_begin(NULL, ISC_FALSE);
201	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
202
203	result = test_master("testdata/master/master4.data",
204			     dns_masterformat_text);
205	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
206
207	dns_test_end();
208}
209
210
211/* Bad class test */
212ATF_TC(badclass);
213ATF_TC_HEAD(badclass, tc) {
214	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
215				       "DNS_R_BADCLASS when record class "
216				       "doesn't match zone class");
217}
218ATF_TC_BODY(badclass, tc) {
219	isc_result_t result;
220
221	UNUSED(tc);
222
223	result = dns_test_begin(NULL, ISC_FALSE);
224	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
225
226	result = test_master("testdata/master/master5.data",
227			     dns_masterformat_text);
228	ATF_REQUIRE_EQ(result, DNS_R_BADCLASS);
229
230	dns_test_end();
231}
232
233/* Too big rdata test */
234ATF_TC(toobig);
235ATF_TC_HEAD(toobig, tc) {
236	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
237				       "ISC_R_NOSPACE when record is too big");
238}
239ATF_TC_BODY(toobig, tc) {
240	isc_result_t result;
241
242	UNUSED(tc);
243
244	result = dns_test_begin(NULL, ISC_FALSE);
245	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
246
247	result = test_master("testdata/master/master15.data",
248			     dns_masterformat_text);
249	ATF_REQUIRE_EQ(result, ISC_R_NOSPACE);
250
251	dns_test_end();
252}
253
254/* Maximum rdata test */
255ATF_TC(maxrdata);
256ATF_TC_HEAD(maxrdata, tc) {
257	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
258				       "ISC_R_SUCCESS when record is maximum "
259				       "size");
260}
261ATF_TC_BODY(maxrdata, tc) {
262	isc_result_t result;
263
264	UNUSED(tc);
265
266	result = dns_test_begin(NULL, ISC_FALSE);
267	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
268
269	result = test_master("testdata/master/master16.data",
270			     dns_masterformat_text);
271	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
272
273	dns_test_end();
274}
275
276/* DNSKEY test */
277ATF_TC(dnskey);
278ATF_TC_HEAD(dnskey, tc) {
279	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
280				       "DNSKEY with key material");
281}
282ATF_TC_BODY(dnskey, tc) {
283	isc_result_t result;
284
285	UNUSED(tc);
286
287	result = dns_test_begin(NULL, ISC_FALSE);
288	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
289
290	result = test_master("testdata/master/master6.data",
291			     dns_masterformat_text);
292	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
293
294	dns_test_end();
295}
296
297
298/* DNSKEY with no key material test */
299ATF_TC(dnsnokey);
300ATF_TC_HEAD(dnsnokey, tc) {
301	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
302				       "DNSKEY with no key material");
303}
304ATF_TC_BODY(dnsnokey, tc) {
305	isc_result_t result;
306
307	UNUSED(tc);
308
309	result = dns_test_begin(NULL, ISC_FALSE);
310	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
311
312	result = test_master("testdata/master/master7.data",
313			     dns_masterformat_text);
314	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
315
316	dns_test_end();
317}
318
319/* Include test */
320ATF_TC(include);
321ATF_TC_HEAD(include, tc) {
322	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
323				       "$INCLUDE");
324}
325ATF_TC_BODY(include, tc) {
326	isc_result_t result;
327
328	UNUSED(tc);
329
330	result = dns_test_begin(NULL, ISC_FALSE);
331	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
332
333	result = test_master("testdata/master/master8.data",
334			     dns_masterformat_text);
335	ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE);
336
337	dns_test_end();
338}
339
340/* Include failure test */
341ATF_TC(includefail);
342ATF_TC_HEAD(includefail, tc) {
343	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
344				       "$INCLUDE failures");
345}
346ATF_TC_BODY(includefail, tc) {
347	isc_result_t result;
348
349	UNUSED(tc);
350
351	result = dns_test_begin(NULL, ISC_FALSE);
352	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
353
354	result = test_master("testdata/master/master9.data",
355			     dns_masterformat_text);
356	ATF_REQUIRE_EQ(result, DNS_R_BADCLASS);
357
358	dns_test_end();
359}
360
361
362/* Non-empty blank lines test */
363ATF_TC(blanklines);
364ATF_TC_HEAD(blanklines, tc) {
365	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() handles "
366				       "non-empty blank lines");
367}
368ATF_TC_BODY(blanklines, tc) {
369	isc_result_t result;
370
371	UNUSED(tc);
372
373	result = dns_test_begin(NULL, ISC_FALSE);
374	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
375
376	result = test_master("testdata/master/master10.data",
377			     dns_masterformat_text);
378	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
379
380	dns_test_end();
381}
382
383/* SOA leading zeroes test */
384ATF_TC(leadingzero);
385ATF_TC_HEAD(leadingzero, tc) {
386	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() allows "
387				       "leading zeroes in SOA");
388}
389ATF_TC_BODY(leadingzero, tc) {
390	isc_result_t result;
391
392	UNUSED(tc);
393
394	result = dns_test_begin(NULL, ISC_FALSE);
395	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
396
397	result = test_master("testdata/master/master11.data",
398			     dns_masterformat_text);
399	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
400
401	dns_test_end();
402}
403
404ATF_TC(totext);
405ATF_TC_HEAD(totext, tc) {
406	atf_tc_set_md_var(tc, "descr", "masterfile totext tests");
407}
408ATF_TC_BODY(totext, tc) {
409	isc_result_t result;
410	dns_rdataset_t rdataset;
411	dns_rdatalist_t rdatalist;
412	isc_buffer_t target;
413	unsigned char buf[BIGBUFLEN];
414
415	UNUSED(tc);
416
417	result = dns_test_begin(NULL, ISC_FALSE);
418	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
419
420	/* First, test with an empty rdataset */
421	rdatalist.rdclass = dns_rdataclass_in;
422	rdatalist.type = dns_rdatatype_none;
423	rdatalist.covers = dns_rdatatype_none;
424	rdatalist.ttl = 0;
425	ISC_LIST_INIT(rdatalist.rdata);
426	ISC_LINK_INIT(&rdatalist, link);
427
428	dns_rdataset_init(&rdataset);
429	result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
430	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
431
432	isc_buffer_init(&target, buf, BIGBUFLEN);
433	result = dns_master_rdatasettotext(dns_rootname,
434					   &rdataset, &dns_master_style_debug,
435					   &target);
436	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
437	ATF_CHECK_EQ(isc_buffer_usedlength(&target), 0);
438
439	/*
440	 * XXX: We will also need to add tests for dumping various
441	 * rdata types, classes, etc, and comparing the results against
442	 * known-good output.
443	 */
444
445	dns_test_end();
446}
447
448/* Raw load */
449ATF_TC(loadraw);
450ATF_TC_HEAD(loadraw, tc) {
451	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() loads a "
452				       "valid raw file and returns success");
453}
454ATF_TC_BODY(loadraw, tc) {
455	isc_result_t result;
456
457	UNUSED(tc);
458
459	result = dns_test_begin(NULL, ISC_FALSE);
460	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
461
462	/* Raw format version 0 */
463	result = test_master("testdata/master/master12.data",
464			     dns_masterformat_raw);
465	ATF_CHECK_STREQ(isc_result_totext(result), "success");
466	ATF_CHECK(headerset);
467	ATF_CHECK_EQ(header.flags, 0);
468
469	/* Raw format version 1, no source serial  */
470	result = test_master("testdata/master/master13.data",
471			     dns_masterformat_raw);
472	ATF_CHECK_STREQ(isc_result_totext(result), "success");
473	ATF_CHECK(headerset);
474	ATF_CHECK_EQ(header.flags, 0);
475
476	/* Raw format version 1, source serial == 2011120101 */
477	result = test_master("testdata/master/master14.data",
478			     dns_masterformat_raw);
479	ATF_CHECK_STREQ(isc_result_totext(result), "success");
480	ATF_CHECK(headerset);
481	ATF_CHECK((header.flags & DNS_MASTERRAW_SOURCESERIALSET) != 0);
482	ATF_CHECK_EQ(header.sourceserial, 2011120101);
483
484	dns_test_end();
485}
486
487/* Raw dump*/
488ATF_TC(dumpraw);
489ATF_TC_HEAD(dumpraw, tc) {
490	atf_tc_set_md_var(tc, "descr", "dns_master_dump*() functions "
491				       "dump valid raw files");
492}
493ATF_TC_BODY(dumpraw, tc) {
494	isc_result_t result;
495	dns_db_t *db = NULL;
496	dns_dbversion_t *version = NULL;
497	char origin[sizeof(TEST_ORIGIN)];
498	dns_name_t dns_origin;
499	isc_buffer_t source, target;
500	unsigned char name_buf[BUFLEN];
501	int len;
502
503	UNUSED(tc);
504
505	strcpy(origin, TEST_ORIGIN);
506	len = strlen(origin);
507	isc_buffer_init(&source, origin, len);
508	isc_buffer_add(&source, len);
509	isc_buffer_setactive(&source, len);
510	isc_buffer_init(&target, name_buf, BUFLEN);
511	dns_name_init(&dns_origin, NULL);
512	result = dns_name_fromtext(&dns_origin, &source, dns_rootname,
513				   0, &target);
514	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
515
516	result = dns_test_begin(NULL, ISC_FALSE);
517	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
518
519	result = dns_db_create(mctx, "rbt", &dns_origin, dns_dbtype_zone,
520			       dns_rdataclass_in, 0, NULL, &db);
521	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
522
523	result = dns_db_load(db, "testdata/master/master1.data");
524	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
525
526	dns_db_currentversion(db, &version);
527
528	result = dns_master_dump2(mctx, db, version,
529				  &dns_master_style_default, "test.dump",
530				  dns_masterformat_raw);
531	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
532
533	result = test_master("test.dump", dns_masterformat_raw);
534	ATF_CHECK_STREQ(isc_result_totext(result), "success");
535	ATF_CHECK(headerset);
536	ATF_CHECK_EQ(header.flags, 0);
537
538	dns_master_initrawheader(&header);
539	header.sourceserial = 12345;
540	header.flags |= DNS_MASTERRAW_SOURCESERIALSET;
541
542	unlink("test.dump");
543	result = dns_master_dump3(mctx, db, version,
544				  &dns_master_style_default, "test.dump",
545				  dns_masterformat_raw, &header);
546	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
547
548	result = test_master("test.dump", dns_masterformat_raw);
549	ATF_CHECK_STREQ(isc_result_totext(result), "success");
550	ATF_CHECK(headerset);
551	ATF_CHECK((header.flags & DNS_MASTERRAW_SOURCESERIALSET) != 0);
552	ATF_CHECK_EQ(header.sourceserial, 12345);
553
554	unlink("test.dump");
555	dns_db_closeversion(db, &version, ISC_FALSE);
556	dns_db_detach(&db);
557	dns_test_end();
558}
559
560/*
561 * Main
562 */
563ATF_TP_ADD_TCS(tp) {
564	ATF_TP_ADD_TC(tp, load);
565	ATF_TP_ADD_TC(tp, unexpected);
566	ATF_TP_ADD_TC(tp, noowner);
567	ATF_TP_ADD_TC(tp, nottl);
568	ATF_TP_ADD_TC(tp, badclass);
569	ATF_TP_ADD_TC(tp, dnskey);
570	ATF_TP_ADD_TC(tp, dnsnokey);
571	ATF_TP_ADD_TC(tp, include);
572	ATF_TP_ADD_TC(tp, includefail);
573	ATF_TP_ADD_TC(tp, blanklines);
574	ATF_TP_ADD_TC(tp, leadingzero);
575	ATF_TP_ADD_TC(tp, totext);
576	ATF_TP_ADD_TC(tp, loadraw);
577	ATF_TP_ADD_TC(tp, dumpraw);
578	ATF_TP_ADD_TC(tp, toobig);
579	ATF_TP_ADD_TC(tp, maxrdata);
580
581	return (atf_no_error());
582}
583
584