1/*
2 * Copyright (C) 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id$ */
18
19/*! \file */
20
21#include <config.h>
22
23#include <atf-c.h>
24
25#include <unistd.h>
26
27#include <dns/cache.h>
28#include <dns/callbacks.h>
29#include <dns/master.h>
30#include <dns/masterdump.h>
31#include <dns/name.h>
32#include <dns/rdata.h>
33#include <dns/rdatalist.h>
34#include <dns/rdataset.h>
35
36#include "dnstest.h"
37
38/*
39 * Helper functions
40 */
41
42#define	BUFLEN		255
43#define	BIGBUFLEN	(64 * 1024)
44#define TEST_ORIGIN	"test"
45
46static isc_result_t
47add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset);
48
49static isc_result_t
50add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset) {
51	char buf[BIGBUFLEN];
52	isc_buffer_t target;
53	isc_result_t result;
54
55	UNUSED(arg);
56
57	isc_buffer_init(&target, buf, BIGBUFLEN);
58	result = dns_rdataset_totext(dataset, owner, ISC_FALSE, ISC_FALSE,
59				     &target);
60	return(result);
61}
62
63static int
64test_master(const char *testfile) {
65	isc_result_t		result;
66	int			len;
67	char			origin[sizeof(TEST_ORIGIN)];
68	dns_name_t		dns_origin;
69	isc_buffer_t		source;
70	isc_buffer_t		target;
71	unsigned char		name_buf[BUFLEN];
72	dns_rdatacallbacks_t	callbacks;
73
74	strcpy(origin, TEST_ORIGIN);
75	len = strlen(origin);
76	isc_buffer_init(&source, origin, len);
77	isc_buffer_add(&source, len);
78	isc_buffer_setactive(&source, len);
79	isc_buffer_init(&target, name_buf, BUFLEN);
80	dns_name_init(&dns_origin, NULL);
81
82	result = dns_name_fromtext(&dns_origin, &source, dns_rootname,
83				   0, &target);
84	if (result != ISC_R_SUCCESS)
85		return(result);
86
87	dns_rdatacallbacks_init_stdio(&callbacks);
88	callbacks.add = add_callback;
89
90	/*
91	 * atf-run changes us to a /tmp directory, so tests
92	 * that access test data files must first chdir to the proper
93	 * location.
94	 */
95	if (chdir(TESTS) == -1)
96		return (ISC_R_FAILURE);
97
98	result = dns_master_loadfile(testfile, &dns_origin, &dns_origin,
99				     dns_rdataclass_in, ISC_TRUE,
100				     &callbacks, mctx);
101	return (result);
102}
103
104/*
105 * Individual unit tests
106 */
107
108/* Successful load test */
109ATF_TC(master_load);
110ATF_TC_HEAD(master_load, tc) {
111	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() loads a "
112				       "valid master file and returns success");
113}
114ATF_TC_BODY(master_load, tc) {
115	isc_result_t result;
116
117	UNUSED(tc);
118
119	result = dns_test_begin(NULL, ISC_FALSE);
120	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
121
122	result = test_master("testdata/master/master1.data");
123	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
124
125	dns_test_end();
126}
127
128
129/* Unepxected end of file test */
130ATF_TC(master_unexpected);
131ATF_TC_HEAD(master_unexpected, tc) {
132	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
133				       "DNS_R_UNEXPECTED when file ends "
134				       "too soon");
135}
136ATF_TC_BODY(master_unexpected, tc) {
137	isc_result_t result;
138
139	UNUSED(tc);
140
141	result = dns_test_begin(NULL, ISC_FALSE);
142	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
143
144	result = test_master("testdata/master/master2.data");
145	ATF_REQUIRE_EQ(result, ISC_R_UNEXPECTEDEND);
146
147	dns_test_end();
148}
149
150
151/* No owner test */
152ATF_TC(master_noowner);
153ATF_TC_HEAD(master_noowner, tc) {
154	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() accepts broken "
155				       "zones with no TTL for first record "
156				       "if it is an SOA");
157}
158ATF_TC_BODY(master_noowner, tc) {
159	isc_result_t result;
160
161	UNUSED(tc);
162
163	result = dns_test_begin(NULL, ISC_FALSE);
164	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
165
166	result = test_master("testdata/master/master3.data");
167	ATF_REQUIRE_EQ(result, DNS_R_NOOWNER);
168
169	dns_test_end();
170}
171
172
173/* No TTL test */
174ATF_TC(master_nottl);
175ATF_TC_HEAD(master_nottl, tc) {
176	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
177				       "DNS_R_NOOWNER when no owner name "
178				       "is specified");
179}
180
181ATF_TC_BODY(master_nottl, tc) {
182	isc_result_t result;
183
184	UNUSED(tc);
185
186	result = dns_test_begin(NULL, ISC_FALSE);
187	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
188
189	result = test_master("testdata/master/master4.data");
190	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
191
192	dns_test_end();
193}
194
195
196/* Bad class test */
197ATF_TC(master_badclass);
198ATF_TC_HEAD(master_badclass, tc) {
199	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
200				       "DNS_R_BADCLASS when record class "
201				       "doesn't match zone class");
202}
203ATF_TC_BODY(master_badclass, tc) {
204	isc_result_t result;
205
206	UNUSED(tc);
207
208	result = dns_test_begin(NULL, ISC_FALSE);
209	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
210
211	result = test_master("testdata/master/master5.data");
212	ATF_REQUIRE_EQ(result, DNS_R_BADCLASS);
213
214	dns_test_end();
215}
216
217/* DNSKEY test */
218ATF_TC(master_dnskey);
219ATF_TC_HEAD(master_dnskey, tc) {
220	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
221				       "DNSKEY with key material");
222}
223ATF_TC_BODY(master_dnskey, tc) {
224	isc_result_t result;
225
226	UNUSED(tc);
227
228	result = dns_test_begin(NULL, ISC_FALSE);
229	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
230
231	result = test_master("testdata/master/master6.data");
232	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
233
234	dns_test_end();
235}
236
237
238/* DNSKEY with no key material test */
239ATF_TC(master_dnsnokey);
240ATF_TC_HEAD(master_dnsnokey, tc) {
241	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
242				       "DNSKEY with no key material");
243}
244ATF_TC_BODY(master_dnsnokey, tc) {
245	isc_result_t result;
246
247	UNUSED(tc);
248
249	result = dns_test_begin(NULL, ISC_FALSE);
250	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
251
252	result = test_master("testdata/master/master7.data");
253	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
254
255	dns_test_end();
256}
257
258/* Include test */
259ATF_TC(master_include);
260ATF_TC_HEAD(master_include, tc) {
261	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
262				       "$INCLUDE");
263}
264ATF_TC_BODY(master_include, tc) {
265	isc_result_t result;
266
267	UNUSED(tc);
268
269	result = dns_test_begin(NULL, ISC_FALSE);
270	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
271
272	result = test_master("testdata/master/master8.data");
273	ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE);
274
275	dns_test_end();
276}
277
278/* Include failure test */
279ATF_TC(master_includefail);
280ATF_TC_HEAD(master_includefail, tc) {
281	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
282				       "$INCLUDE failures");
283}
284ATF_TC_BODY(master_includefail, tc) {
285	isc_result_t result;
286
287	UNUSED(tc);
288
289	result = dns_test_begin(NULL, ISC_FALSE);
290	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
291
292	result = test_master("testdata/master/master9.data");
293	ATF_REQUIRE_EQ(result, DNS_R_BADCLASS);
294
295	dns_test_end();
296}
297
298
299/* Non-empty blank lines test */
300ATF_TC(master_blanklines);
301ATF_TC_HEAD(master_blanklines, tc) {
302	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() handles "
303				       "non-empty blank lines");
304}
305ATF_TC_BODY(master_blanklines, tc) {
306	isc_result_t result;
307
308	UNUSED(tc);
309
310	result = dns_test_begin(NULL, ISC_FALSE);
311	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
312
313	result = test_master("testdata/master/master10.data");
314	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
315
316	dns_test_end();
317}
318
319/* SOA leading zeroes test */
320ATF_TC(master_leadingzero);
321ATF_TC_HEAD(master_leadingzero, tc) {
322	atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() allows "
323				       "leading zeroes in SOA");
324}
325ATF_TC_BODY(master_leadingzero, 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/master11.data");
334	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
335
336	dns_test_end();
337}
338
339ATF_TC(master_totext);
340ATF_TC_HEAD(master_totext, tc) {
341	atf_tc_set_md_var(tc, "descr", "masterfile totext tests");
342}
343ATF_TC_BODY(master_totext, tc) {
344	isc_result_t result;
345	dns_rdataset_t rdataset;
346	dns_rdatalist_t rdatalist;
347	isc_buffer_t target;
348	unsigned char buf[BIGBUFLEN];
349
350	UNUSED(tc);
351
352	result = dns_test_begin(NULL, ISC_FALSE);
353	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
354
355	/* First, test with an empty rdataset */
356	rdatalist.rdclass = dns_rdataclass_in;
357	rdatalist.type = dns_rdatatype_none;
358	rdatalist.covers = dns_rdatatype_none;
359	rdatalist.ttl = 0;
360	ISC_LIST_INIT(rdatalist.rdata);
361	ISC_LINK_INIT(&rdatalist, link);
362
363	dns_rdataset_init(&rdataset);
364	result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
365	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
366
367	isc_buffer_init(&target, buf, BIGBUFLEN);
368	result = dns_master_rdatasettotext(dns_rootname,
369					   &rdataset, &dns_master_style_debug,
370					   &target);
371	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
372	ATF_CHECK_EQ(isc_buffer_usedlength(&target), 0);
373
374	/*
375	 * XXX: We will also need to add tests for dumping various
376	 * rdata types, classes, etc, and comparing the results against
377	 * known-good output.
378	 */
379
380	dns_test_end();
381}
382
383/*
384 * Main
385 */
386ATF_TP_ADD_TCS(tp) {
387	ATF_TP_ADD_TC(tp, master_load);
388	ATF_TP_ADD_TC(tp, master_unexpected);
389	ATF_TP_ADD_TC(tp, master_noowner);
390	ATF_TP_ADD_TC(tp, master_nottl);
391	ATF_TP_ADD_TC(tp, master_badclass);
392	ATF_TP_ADD_TC(tp, master_dnskey);
393	ATF_TP_ADD_TC(tp, master_dnsnokey);
394	ATF_TP_ADD_TC(tp, master_include);
395	ATF_TP_ADD_TC(tp, master_includefail);
396	ATF_TP_ADD_TC(tp, master_blanklines);
397	ATF_TP_ADD_TC(tp, master_leadingzero);
398	ATF_TP_ADD_TC(tp, master_totext);
399
400	return (atf_no_error());
401}
402
403