1/*
2 * Copyright (C) 2004, 2005, 2007, 2009, 2011  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001  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: adb_test.c,v 1.70.346.2 2011/08/30 23:45:51 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include <isc/app.h>
29#include <isc/buffer.h>
30#include <isc/entropy.h>
31#include <isc/hash.h>
32#include <isc/socket.h>
33#include <isc/task.h>
34#include <isc/timer.h>
35#include <isc/util.h>
36
37#include <dns/adb.h>
38#include <dns/cache.h>
39#include <dns/dispatch.h>
40#include <dns/db.h>
41#include <dns/log.h>
42#include <dns/rootns.h>
43#include <dns/result.h>
44
45typedef struct client client_t;
46struct client {
47	dns_name_t		name;
48	const char	       *target;
49	ISC_LINK(client_t)	link;
50	dns_adbfind_t	       *find;
51};
52
53static isc_mem_t *mctx = NULL;
54static isc_entropy_t *ectx = NULL;
55static isc_mempool_t *cmp;
56static isc_log_t *lctx;
57static isc_logconfig_t *lcfg;
58static isc_taskmgr_t *taskmgr;
59static isc_socketmgr_t *socketmgr;
60static isc_timermgr_t *timermgr;
61static dns_dispatchmgr_t *dispatchmgr;
62static isc_task_t *t1, *t2;
63static dns_view_t *view;
64static dns_db_t *rootdb;
65static ISC_LIST(client_t) clients;
66static isc_mutex_t client_lock;
67static isc_stdtime_t now;
68static dns_adb_t *adb;
69
70static void
71check_result(isc_result_t result, const char *format, ...)
72     ISC_FORMAT_PRINTF(2, 3);
73
74static void
75check_result(isc_result_t result, const char *format, ...) {
76	va_list args;
77
78	if (result == ISC_R_SUCCESS)
79		return;
80
81	va_start(args, format);
82	vfprintf(stderr, format, args);
83	va_end(args);
84	fprintf(stderr, ": %s\n", isc_result_totext(result));
85	exit(1);
86}
87
88static client_t *
89new_client(void) {
90	client_t *client;
91
92	client = isc_mempool_get(cmp);
93	INSIST(client != NULL);
94	dns_name_init(&client->name, NULL);
95	ISC_LINK_INIT(client, link);
96	client->find = NULL;
97
98	return (client);
99}
100
101static void
102free_client(client_t **c) {
103	client_t *client;
104
105	INSIST(c != NULL);
106	client = *c;
107	*c = NULL;
108	INSIST(client != NULL);
109	dns_name_free(&client->name, mctx);
110	INSIST(!ISC_LINK_LINKED(client, link));
111	INSIST(client->find == NULL);
112
113	isc_mempool_put(cmp, client);
114}
115
116static inline void
117CLOCK(void) {
118	RUNTIME_CHECK(isc_mutex_lock(&client_lock) == ISC_R_SUCCESS);
119}
120
121static inline void
122CUNLOCK(void) {
123	RUNTIME_CHECK(isc_mutex_unlock(&client_lock) == ISC_R_SUCCESS);
124}
125
126static void
127lookup_callback(isc_task_t *task, isc_event_t *ev) {
128	client_t *client;
129
130	client = ev->ev_arg;
131	INSIST(client->find == ev->ev_sender);
132
133	printf("NAME %s:\n\tTask %p got event %p type %08x from %p, client %p\n\terr4: %s  err6: %s\n",
134	       client->target,
135	       task, ev, ev->ev_type, client->find, client,
136	       isc_result_totext(client->find->result_v4),
137	       isc_result_totext(client->find->result_v6));
138
139	isc_event_free(&ev);
140	ev = NULL;
141
142	CLOCK();
143
144	dns_adb_dumpfind(client->find, stderr);
145	dns_adb_destroyfind(&client->find);
146
147	ISC_LIST_UNLINK(clients, client, link);
148	free_client(&client);
149
150	CUNLOCK();
151}
152
153static void
154create_managers(void) {
155	isc_result_t result;
156
157	taskmgr = NULL;
158	result = isc_taskmgr_create(mctx, 5, 0, &taskmgr);
159	check_result(result, "isc_taskmgr_create");
160
161	timermgr = NULL;
162	result = isc_timermgr_create(mctx, &timermgr);
163	check_result(result, "isc_timermgr_create");
164
165	socketmgr = NULL;
166	result = isc_socketmgr_create(mctx, &socketmgr);
167	check_result(result, "isc_socketmgr_create");
168
169	dispatchmgr = NULL;
170	result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
171	check_result(result, "dns_dispatchmgr_create");
172}
173
174static void
175create_view(void) {
176	dns_cache_t *cache;
177	isc_result_t result;
178
179	/*
180	 * View.
181	 */
182	view = NULL;
183	result = dns_view_create(mctx, dns_rdataclass_in, "_default", &view);
184	check_result(result, "dns_view_create");
185
186	/*
187	 * Cache.
188	 */
189	cache = NULL;
190	result = dns_cache_create(mctx, taskmgr, timermgr, dns_rdataclass_in,
191				  "rbt", 0, NULL, &cache);
192	check_result(result, "dns_cache_create");
193	dns_view_setcache(view, cache);
194	dns_cache_detach(&cache);
195
196	{
197		unsigned int attrs;
198		isc_sockaddr_t any4, any6;
199		dns_dispatch_t *disp4 = NULL;
200		dns_dispatch_t *disp6 = NULL;
201
202		isc_sockaddr_any(&any4);
203		isc_sockaddr_any6(&any6);
204
205		attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
206		RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr,
207						  taskmgr, &any4, 512, 6, 1024,
208						  17, 19, attrs, attrs, &disp4)
209			      == ISC_R_SUCCESS);
210		INSIST(disp4 != NULL);
211
212		attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP;
213		RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr,
214						  taskmgr, &any6, 512, 6, 1024,
215						  17, 19, attrs, attrs, &disp6)
216			      == ISC_R_SUCCESS);
217		INSIST(disp6 != NULL);
218
219		RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10,
220						      socketmgr,
221						      timermgr, 0,
222						      dispatchmgr,
223						      disp4, disp6) ==
224		      ISC_R_SUCCESS);
225	}
226
227	rootdb = NULL;
228	result = dns_rootns_create(mctx, dns_rdataclass_in, NULL, &rootdb);
229	check_result(result, "dns_rootns_create()");
230	dns_view_sethints(view, rootdb);
231	dns_db_detach(&rootdb);
232
233	dns_view_freeze(view);
234}
235
236static void
237lookup(const char *target) {
238	dns_name_t name;
239	unsigned char namedata[256];
240	client_t *client;
241	isc_buffer_t t, namebuf;
242	isc_result_t result;
243	unsigned int options;
244
245	INSIST(target != NULL);
246
247	client = new_client();
248	isc_buffer_init(&t, target, strlen(target));
249	isc_buffer_add(&t, strlen(target));
250	isc_buffer_init(&namebuf, namedata, sizeof(namedata));
251	dns_name_init(&name, NULL);
252	result = dns_name_fromtext(&name, &t, dns_rootname, 0, &namebuf);
253	check_result(result, "dns_name_fromtext %s", target);
254
255	result = dns_name_dup(&name, mctx, &client->name);
256	check_result(result, "dns_name_dup %s", target);
257
258	options = 0;
259	options |= DNS_ADBFIND_INET;
260	options |= DNS_ADBFIND_INET6;
261	options |= DNS_ADBFIND_WANTEVENT;
262	options |= DNS_ADBFIND_HINTOK;
263	options |= DNS_ADBFIND_GLUEOK;
264	result = dns_adb_createfind(adb, t2, lookup_callback, client,
265				    &client->name, dns_rootname, 0, options,
266				    now, NULL, view->dstport, &client->find);
267	if (result != ISC_R_SUCCESS)
268		printf("DNS_ADB_CREATEFIND -> %s\n", dns_result_totext(result));
269	dns_adb_dumpfind(client->find, stderr);
270
271	if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
272		client->target = target;
273		ISC_LIST_APPEND(clients, client, link);
274	} else {
275		printf("NAME %s:  err4 %s, err6 %s\n",
276		       target, isc_result_totext(client->find->result_v4),
277		       isc_result_totext(client->find->result_v6));
278
279		dns_adb_destroyfind(&client->find);
280		free_client(&client);
281	}
282}
283
284int
285main(int argc, char **argv) {
286	isc_result_t result;
287	isc_logdestination_t destination;
288
289	UNUSED(argc);
290	UNUSED(argv);
291
292	dns_result_register();
293	result = isc_app_start();
294	check_result(result, "isc_app_start()");
295
296	isc_stdtime_get(&now);
297
298	result = isc_mutex_init(&client_lock);
299	check_result(result, "isc_mutex_init(&client_lock)");
300	ISC_LIST_INIT(clients);
301
302	/*
303	 * EVERYTHING needs a memory context.
304	 */
305	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
306
307	cmp = NULL;
308	RUNTIME_CHECK(isc_mempool_create(mctx, sizeof(client_t), &cmp)
309		      == ISC_R_SUCCESS);
310	isc_mempool_setname(cmp, "adb test clients");
311
312	result = isc_entropy_create(mctx, &ectx);
313	check_result(result, "isc_entropy_create()");
314	result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
315	check_result(result, "isc_hash_create()");
316
317	result = isc_log_create(mctx, &lctx, &lcfg);
318	check_result(result, "isc_log_create()");
319	isc_log_setcontext(lctx);
320	dns_log_init(lctx);
321	dns_log_setcontext(lctx);
322
323	/*
324	 * Create and install the default channel.
325	 */
326	destination.file.stream = stderr;
327	destination.file.name = NULL;
328	destination.file.versions = ISC_LOG_ROLLNEVER;
329	destination.file.maximum_size = 0;
330	result = isc_log_createchannel(lcfg, "_default",
331				       ISC_LOG_TOFILEDESC,
332				       ISC_LOG_DYNAMIC,
333				       &destination, ISC_LOG_PRINTTIME);
334	check_result(result, "isc_log_createchannel()");
335	result = isc_log_usechannel(lcfg, "_default", NULL, NULL);
336	check_result(result, "isc_log_usechannel()");
337
338	/*
339	 * Set the initial debug level.
340	 */
341	isc_log_setdebuglevel(lctx, 2);
342
343	create_managers();
344
345	t1 = NULL;
346	result = isc_task_create(taskmgr, 0, &t1);
347	check_result(result, "isc_task_create t1");
348	t2 = NULL;
349	result = isc_task_create(taskmgr, 0, &t2);
350	check_result(result, "isc_task_create t2");
351
352	printf("task 1 = %p\n", t1);
353	printf("task 2 = %p\n", t2);
354
355	create_view();
356
357	adb = view->adb;
358
359	/*
360	 * Lock the entire client list here.  This will cause all events
361	 * for found names to block as well.
362	 */
363	CLOCK();
364	lookup("f.root-servers.net.");		/* Should be in hints */
365	lookup("www.iengines.com");		/* should fetch */
366	lookup("www.isc.org");			/* should fetch */
367	lookup("www.flame.org");		/* should fetch */
368	lookup("kechara.flame.org.");		/* should fetch */
369	lookup("moghedien.flame.org.");		/* should fetch */
370	lookup("mailrelay.flame.org.");		/* should fetch */
371	lookup("ipv4v6.flame.org.");		/* should fetch */
372	lookup("nonexistant.flame.org.");	/* should fail to be found */
373	lookup("foobar.badns.flame.org.");	/* should fail utterly (NS) */
374	lookup("i.root-servers.net.");		/* Should be in hints */
375	lookup("www.firstcard.com.");
376	lookup("dns04.flame.org.");
377	CUNLOCK();
378
379	sleep(10);
380
381	dns_adb_dump(adb, stderr);
382
383	sleep(10);
384
385	CLOCK();
386	lookup("f.root-servers.net.");		/* Should be in hints */
387	lookup("www.iengines.com");		/* should fetch */
388	lookup("www.isc.org");			/* should fetch */
389	lookup("www.flame.org");		/* should fetch */
390	lookup("kechara.flame.org.");		/* should fetch */
391	lookup("moghedien.flame.org.");		/* should fetch */
392	lookup("mailrelay.flame.org.");		/* should fetch */
393	lookup("ipv4v6.flame.org.");		/* should fetch */
394	lookup("nonexistant.flame.org.");	/* should fail to be found */
395	lookup("foobar.badns.flame.org.");	/* should fail utterly (NS) */
396	lookup("i.root-servers.net.");		/* Should be in hints */
397	CUNLOCK();
398
399	sleep(20);
400
401	dns_adb_dump(adb, stderr);
402
403	isc_task_detach(&t1);
404	isc_task_detach(&t2);
405
406	isc_mem_stats(mctx, stdout);
407	dns_adb_dump(adb, stderr);
408
409	isc_app_run();
410
411	dns_adb_dump(adb, stderr);
412
413	dns_view_detach(&view);
414	adb = NULL;
415
416	fprintf(stderr, "Destroying socket manager\n");
417	isc_socketmgr_destroy(&socketmgr);
418	fprintf(stderr, "Destroying timer manager\n");
419	isc_timermgr_destroy(&timermgr);
420
421	fprintf(stderr, "Destroying task manager\n");
422	isc_taskmgr_destroy(&taskmgr);
423
424	isc_log_destroy(&lctx);
425
426	isc_hash_destroy();
427	isc_entropy_detach(&ectx);
428
429	isc_mempool_destroy(&cmp);
430	isc_mem_stats(mctx, stdout);
431	isc_mem_destroy(&mctx);
432
433	isc_app_finish();
434
435	return (0);
436}
437