1/*
2 * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: zone_test.c,v 1.35 2009/09/02 23:48:01 tbox Exp $ */
19
20#include <config.h>
21
22#include <sys/param.h>
23#include <sys/types.h>
24#include <sys/time.h>
25
26#include <unistd.h>
27#include <stdlib.h>
28
29#include <isc/app.h>
30#include <isc/commandline.h>
31#include <isc/mem.h>
32#include <isc/socket.h>
33#include <isc/string.h>
34#include <isc/task.h>
35#include <isc/timer.h>
36#include <isc/util.h>
37
38#include <dns/db.h>
39#include <dns/fixedname.h>
40#include <dns/rdataclass.h>
41#include <dns/rdataset.h>
42#include <dns/result.h>
43#include <dns/zone.h>
44
45#ifdef ISC_PLATFORM_NEEDSYSSELECTH
46#include <sys/select.h>
47#endif
48
49static int debug = 0;
50static int quiet = 0;
51static int stats = 0;
52static isc_mem_t *mctx = NULL;
53dns_zone_t *zone = NULL;
54isc_taskmgr_t *taskmgr = NULL;
55isc_timermgr_t *timermgr = NULL;
56isc_socketmgr_t *socketmgr = NULL;
57dns_zonemgr_t *zonemgr = NULL;
58dns_zonetype_t zonetype = dns_zone_master;
59isc_sockaddr_t addr;
60
61#define ERRRET(result, function) \
62	do { \
63		if (result != ISC_R_SUCCESS) { \
64			fprintf(stderr, "%s() returned %s\n", \
65				function, dns_result_totext(result)); \
66			return; \
67		} \
68	} while (0)
69
70#define ERRCONT(result, function) \
71		if (result != ISC_R_SUCCESS) { \
72			fprintf(stderr, "%s() returned %s\n", \
73				function, dns_result_totext(result)); \
74			continue; \
75		} else \
76			(void)NULL
77
78static void
79usage() {
80	fprintf(stderr,
81		"usage: zone_test [-dqsSM] [-c class] [-f file] zone\n");
82	exit(1);
83}
84
85static void
86setup(const char *zonename, const char *filename, const char *classname) {
87	isc_result_t result;
88	dns_rdataclass_t rdclass;
89	isc_consttextregion_t region;
90	isc_buffer_t buffer;
91	dns_fixedname_t fixorigin;
92	dns_name_t *origin;
93	const char *rbt = "rbt";
94
95	if (debug)
96		fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
97			zonename, filename, classname);
98	result = dns_zone_create(&zone, mctx);
99	ERRRET(result, "dns_zone_new");
100
101	dns_zone_settype(zone, zonetype);
102
103	isc_buffer_init(&buffer, zonename, strlen(zonename));
104	isc_buffer_add(&buffer, strlen(zonename));
105	dns_fixedname_init(&fixorigin);
106	result = dns_name_fromtext(dns_fixedname_name(&fixorigin),
107				   &buffer, dns_rootname, 0, NULL);
108	ERRRET(result, "dns_name_fromtext");
109	origin = dns_fixedname_name(&fixorigin);
110
111	result = dns_zone_setorigin(zone, origin);
112	ERRRET(result, "dns_zone_setorigin");
113
114	result = dns_zone_setdbtype(zone, 1, &rbt);
115	ERRRET(result, "dns_zone_setdatabase");
116
117	result = dns_zone_setfile(zone, filename);
118	ERRRET(result, "dns_zone_setfile");
119
120	region.base = classname;
121	region.length = strlen(classname);
122	result = dns_rdataclass_fromtext(&rdclass,
123					 (isc_textregion_t *)(void*)&region);
124	ERRRET(result, "dns_rdataclass_fromtext");
125
126	dns_zone_setclass(zone, rdclass);
127
128	if (zonetype == dns_zone_slave)
129		dns_zone_setmasters(zone, &addr, 1);
130
131	result = dns_zone_load(zone);
132	ERRRET(result, "dns_zone_load");
133
134	result = dns_zonemgr_managezone(zonemgr, zone);
135	ERRRET(result, "dns_zonemgr_managezone");
136}
137
138static void
139print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) {
140	isc_buffer_t text;
141	char t[1000];
142	isc_result_t result;
143	isc_region_t r;
144
145	isc_buffer_init(&text, t, sizeof(t));
146	result = dns_rdataset_totext(rdataset, name, ISC_FALSE, ISC_FALSE,
147				     &text);
148	isc_buffer_usedregion(&text, &r);
149	if (result == ISC_R_SUCCESS)
150		printf("%.*s", (int)r.length, (char *)r.base);
151	else
152		printf("%s\n", dns_result_totext(result));
153}
154
155static void
156query(void) {
157	char buf[1024];
158	dns_fixedname_t name;
159	dns_fixedname_t found;
160	dns_db_t *db;
161	char *s;
162	isc_buffer_t buffer;
163	isc_result_t result;
164	dns_rdataset_t rdataset;
165	dns_rdataset_t sigset;
166	fd_set rfdset;
167
168	db = NULL;
169	result = dns_zone_getdb(zone, &db);
170	if (result != ISC_R_SUCCESS) {
171		fprintf(stderr, "%s() returned %s\n", "dns_zone_getdb",
172			dns_result_totext(result));
173		return;
174	}
175
176	dns_fixedname_init(&found);
177	dns_rdataset_init(&rdataset);
178	dns_rdataset_init(&sigset);
179
180	do {
181
182		fprintf(stdout, "zone_test ");
183		fflush(stdout);
184		FD_ZERO(&rfdset);
185		FD_SET(0, &rfdset);
186		select(1, &rfdset, NULL, NULL, NULL);
187		if (fgets(buf, sizeof(buf), stdin) == NULL) {
188			fprintf(stdout, "\n");
189			break;
190		}
191		buf[sizeof(buf) - 1] = '\0';
192
193		s = strchr(buf, '\n');
194		if (s != NULL)
195			*s = '\0';
196		s = strchr(buf, '\r');
197		if (s != NULL)
198			*s = '\0';
199		if (strcmp(buf, "dump") == 0) {
200			dns_zone_dumptostream(zone, stdout);
201			continue;
202		}
203		if (strlen(buf) == 0U)
204			continue;
205		dns_fixedname_init(&name);
206		isc_buffer_init(&buffer, buf, strlen(buf));
207		isc_buffer_add(&buffer, strlen(buf));
208		result = dns_name_fromtext(dns_fixedname_name(&name),
209				  &buffer, dns_rootname, 0, NULL);
210		ERRCONT(result, "dns_name_fromtext");
211
212		result = dns_db_find(db, dns_fixedname_name(&name),
213				     NULL /*vesion*/,
214				     dns_rdatatype_a,
215				     0 /*options*/,
216				     0 /*time*/,
217				     NULL /*nodep*/,
218				     dns_fixedname_name(&found),
219				     &rdataset, &sigset);
220		fprintf(stderr, "%s() returned %s\n", "dns_db_find",
221			dns_result_totext(result));
222		switch (result) {
223		case DNS_R_DELEGATION:
224			print_rdataset(dns_fixedname_name(&found), &rdataset);
225			break;
226		case ISC_R_SUCCESS:
227			print_rdataset(dns_fixedname_name(&name), &rdataset);
228			break;
229		default:
230			break;
231		}
232
233		if (dns_rdataset_isassociated(&rdataset))
234			dns_rdataset_disassociate(&rdataset);
235		if (dns_rdataset_isassociated(&sigset))
236			dns_rdataset_disassociate(&sigset);
237	} while (1);
238	dns_rdataset_invalidate(&rdataset);
239	dns_db_detach(&db);
240}
241
242int
243main(int argc, char **argv) {
244	int c;
245	char *filename = NULL;
246	const char *classname = "IN";
247
248	while ((c = isc_commandline_parse(argc, argv, "cdf:m:qsMS")) != EOF) {
249		switch (c) {
250		case 'c':
251			classname = isc_commandline_argument;
252			break;
253		case 'd':
254			debug++;
255			break;
256		case 'f':
257			if (filename != NULL)
258				usage();
259			filename = isc_commandline_argument;
260			break;
261		case 'm':
262			memset(&addr, 0, sizeof(addr));
263			addr.type.sin.sin_family = AF_INET;
264			inet_pton(AF_INET, isc_commandline_argument,
265				  &addr.type.sin.sin_addr);
266			addr.type.sin.sin_port = htons(53);
267			break;
268		case 'q':
269			quiet++;
270			break;
271		case 's':
272			stats++;
273			break;
274		case 'S':
275			zonetype = dns_zone_slave;
276			break;
277		case 'M':
278			zonetype = dns_zone_master;
279			break;
280		default:
281			usage();
282		}
283	}
284
285	if (argv[isc_commandline_index] == NULL)
286		usage();
287
288	RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
289	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
290	RUNTIME_CHECK(isc_taskmgr_create(mctx, 2, 0, &taskmgr) ==
291		      ISC_R_SUCCESS);
292	RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
293	RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
294	RUNTIME_CHECK(dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
295					 &zonemgr) == ISC_R_SUCCESS);
296	if (filename == NULL)
297		filename = argv[isc_commandline_index];
298	setup(argv[isc_commandline_index], filename, classname);
299	query();
300	if (zone != NULL)
301		dns_zone_detach(&zone);
302	dns_zonemgr_shutdown(zonemgr);
303	dns_zonemgr_detach(&zonemgr);
304	isc_socketmgr_destroy(&socketmgr);
305	isc_taskmgr_destroy(&taskmgr);
306	isc_timermgr_destroy(&timermgr);
307	if (!quiet && stats)
308		isc_mem_stats(mctx, stdout);
309	isc_mem_destroy(&mctx);
310
311	return (0);
312}
313