1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file
15  */
16 
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <isc/app.h>
22 #include <isc/commandline.h>
23 #include <isc/hash.h>
24 #include <isc/managers.h>
25 #include <isc/netaddr.h>
26 #include <isc/print.h>
27 #include <isc/task.h>
28 #include <isc/timer.h>
29 #include <isc/util.h>
30 
31 #include <dns/adb.h>
32 #include <dns/cache.h>
33 #include <dns/dispatch.h>
34 #include <dns/events.h>
35 #include <dns/forward.h>
36 #include <dns/log.h>
37 #include <dns/resolver.h>
38 #include <dns/result.h>
39 
40 static isc_mem_t *mctx = NULL;
41 static isc_nm_t *netmgr = NULL;
42 static isc_taskmgr_t *taskmgr = NULL;
43 static dns_view_t *view = NULL;
44 static dns_adbfind_t *find = NULL;
45 static isc_task_t *task = NULL;
46 static dns_fixedname_t fixed;
47 static dns_fixedname_t target;
48 static isc_log_t *lctx = NULL;
49 static isc_logconfig_t *lcfg = NULL;
50 static unsigned int level = 0;
51 
52 static void
53 adb_callback(isc_task_t *task, isc_event_t *event);
54 
55 static void
log_init(void)56 log_init(void) {
57 	isc_logdestination_t destination;
58 	unsigned int flags;
59 
60 	/*
61 	 * Setup a logging context.
62 	 */
63 	isc_log_create(mctx, &lctx, &lcfg);
64 	isc_log_setcontext(lctx);
65 	dns_log_init(lctx);
66 	dns_log_setcontext(lctx);
67 
68 	/*
69 	 * Create and install the default channel.
70 	 */
71 	destination.file.stream = stderr;
72 	destination.file.name = NULL;
73 	destination.file.versions = ISC_LOG_ROLLNEVER;
74 	destination.file.maximum_size = 0;
75 	flags = ISC_LOG_PRINTTIME;
76 	isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC,
77 			      ISC_LOG_DYNAMIC, &destination, flags);
78 
79 	RUNTIME_CHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL) ==
80 		      ISC_R_SUCCESS);
81 	isc_log_setdebuglevel(lctx, level);
82 }
83 
84 static void
print_addresses(dns_adbfind_t * adbfind)85 print_addresses(dns_adbfind_t *adbfind) {
86 	dns_adbaddrinfo_t *address;
87 
88 	for (address = ISC_LIST_HEAD(adbfind->list); address != NULL;
89 	     address = ISC_LIST_NEXT(address, publink))
90 	{
91 		isc_netaddr_t netaddr;
92 		char text[ISC_NETADDR_FORMATSIZE];
93 		isc_netaddr_fromsockaddr(&netaddr, &address->sockaddr);
94 		isc_netaddr_format(&netaddr, text, sizeof(text));
95 		printf("%s\n", text);
96 	}
97 }
98 
99 static void
print_name(dns_name_t * name)100 print_name(dns_name_t *name) {
101 	char text[DNS_NAME_FORMATSIZE];
102 
103 	dns_name_format(name, text, sizeof(text));
104 	printf("%s\n", text);
105 }
106 
107 static void
do_find(bool want_event)108 do_find(bool want_event) {
109 	isc_result_t result;
110 	bool done = false;
111 	unsigned int options;
112 
113 	options = DNS_ADBFIND_INET | DNS_ADBFIND_INET6;
114 	if (want_event) {
115 		options |= DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
116 	}
117 	dns_fixedname_init(&target);
118 	result = dns_adb_createfind(view->adb, task, adb_callback, NULL,
119 				    dns_fixedname_name(&fixed), dns_rootname, 0,
120 				    options, 0, dns_fixedname_name(&target), 0,
121 				    0, NULL, &find);
122 	if (result == ISC_R_SUCCESS) {
123 		if (!ISC_LIST_EMPTY(find->list)) {
124 			/*
125 			 * We have at least some of the addresses for the
126 			 * name.
127 			 */
128 			INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
129 			print_addresses(find);
130 			done = true;
131 		} else {
132 			/*
133 			 * We don't know any of the addresses for this
134 			 * name.
135 			 */
136 			if ((find->options & DNS_ADBFIND_WANTEVENT) == 0) {
137 				/*
138 				 * And ADB isn't going to send us any events
139 				 * either.  This query loses.
140 				 */
141 				done = true;
142 			}
143 			/*
144 			 * If the DNS_ADBFIND_WANTEVENT flag was set, we'll
145 			 * get an event when something happens.
146 			 */
147 		}
148 	} else if (result == DNS_R_ALIAS) {
149 		print_name(dns_fixedname_name(&target));
150 		done = true;
151 	} else {
152 		printf("dns_adb_createfind() returned %s\n",
153 		       isc_result_totext(result));
154 		done = true;
155 	}
156 
157 	if (done) {
158 		if (find != NULL) {
159 			dns_adb_destroyfind(&find);
160 		}
161 		isc_app_shutdown();
162 	}
163 }
164 
165 static void
adb_callback(isc_task_t * etask,isc_event_t * event)166 adb_callback(isc_task_t *etask, isc_event_t *event) {
167 	unsigned int type = event->ev_type;
168 
169 	REQUIRE(etask == task);
170 
171 	isc_event_free(&event);
172 	dns_adb_destroyfind(&find);
173 
174 	if (type == DNS_EVENT_ADBMOREADDRESSES) {
175 		do_find(false);
176 	} else if (type == DNS_EVENT_ADBNOMOREADDRESSES) {
177 		printf("no more addresses\n");
178 		isc_app_shutdown();
179 	} else {
180 		printf("unexpected ADB event type %u\n", type);
181 		isc_app_shutdown();
182 	}
183 }
184 
185 static void
run(isc_task_t * xtask,isc_event_t * event)186 run(isc_task_t *xtask, isc_event_t *event) {
187 	UNUSED(xtask);
188 	do_find(true);
189 	isc_event_free(&event);
190 }
191 
192 int
main(int argc,char * argv[])193 main(int argc, char *argv[]) {
194 	bool verbose = false;
195 	unsigned int workers = 2;
196 	isc_timermgr_t *timermgr = NULL;
197 	int ch;
198 	isc_socketmgr_t *socketmgr = NULL;
199 	dns_dispatchmgr_t *dispatchmgr = NULL;
200 	dns_cache_t *cache = NULL;
201 	isc_buffer_t b;
202 
203 	RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
204 
205 	dns_result_register();
206 
207 	isc_mem_create(&mctx);
208 
209 	while ((ch = isc_commandline_parse(argc, argv, "d:vw:")) != -1) {
210 		switch (ch) {
211 		case 'd':
212 			level = (unsigned int)atoi(isc_commandline_argument);
213 			break;
214 		case 'v':
215 			verbose = true;
216 			break;
217 		case 'w':
218 			workers = (unsigned int)atoi(isc_commandline_argument);
219 			break;
220 		}
221 	}
222 
223 	log_init();
224 
225 	if (verbose) {
226 		printf("%u workers\n", workers);
227 		printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4()));
228 		printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6()));
229 	}
230 
231 	RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr,
232 					  &taskmgr) == ISC_R_SUCCESS);
233 	RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS);
234 	isc_task_setname(task, "byname", NULL);
235 
236 	RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) ==
237 		      ISC_R_SUCCESS);
238 
239 	RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
240 	RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
241 
242 	RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr,
243 				       dns_rdataclass_in, "", "rbt", 0, NULL,
244 				       &cache) == ISC_R_SUCCESS);
245 
246 	RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default",
247 				      &view) == ISC_R_SUCCESS);
248 
249 	{
250 		unsigned int attrs;
251 		dns_dispatch_t *disp4 = NULL;
252 		dns_dispatch_t *disp6 = NULL;
253 
254 		if (isc_net_probeipv4() == ISC_R_SUCCESS) {
255 			isc_sockaddr_t any4;
256 			isc_sockaddr_any(&any4);
257 
258 			attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
259 			RUNTIME_CHECK(
260 				dns_dispatch_getudp(dispatchmgr, socketmgr,
261 						    taskmgr, &any4, 512, 6,
262 						    1024, 17, 19, attrs, attrs,
263 						    &disp4) == ISC_R_SUCCESS);
264 			INSIST(disp4 != NULL);
265 		}
266 
267 		if (isc_net_probeipv6() == ISC_R_SUCCESS) {
268 			isc_sockaddr_t any6;
269 
270 			isc_sockaddr_any6(&any6);
271 
272 			attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP;
273 			RUNTIME_CHECK(
274 				dns_dispatch_getudp(dispatchmgr, socketmgr,
275 						    taskmgr, &any6, 512, 6,
276 						    1024, 17, 19, attrs, attrs,
277 						    &disp6) == ISC_R_SUCCESS);
278 			INSIST(disp6 != NULL);
279 		}
280 
281 		RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1,
282 						      socketmgr, timermgr, 0,
283 						      dispatchmgr, disp4,
284 						      disp6) == ISC_R_SUCCESS);
285 
286 		if (disp4 != NULL) {
287 			dns_dispatch_detach(&disp4);
288 		}
289 		if (disp6 != NULL) {
290 			dns_dispatch_detach(&disp6);
291 		}
292 	}
293 
294 	{
295 		struct in_addr ina;
296 		isc_sockaddr_t sa;
297 		isc_sockaddrlist_t sal;
298 
299 		ISC_LIST_INIT(sal);
300 		ina.s_addr = inet_addr("127.0.0.1");
301 		isc_sockaddr_fromin(&sa, &ina, 53);
302 		ISC_LIST_APPEND(sal, &sa, link);
303 
304 		REQUIRE(DNS_VIEW_VALID(view));
305 		RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname,
306 					       &sal, dns_fwdpolicy_only) ==
307 			      ISC_R_SUCCESS);
308 	}
309 
310 	dns_view_setcache(view, cache, false);
311 	dns_view_freeze(view);
312 
313 	dns_cache_detach(&cache);
314 
315 	printf("name = %s\n", argv[isc_commandline_index]);
316 	isc_buffer_init(&b, argv[isc_commandline_index],
317 			strlen(argv[isc_commandline_index]));
318 	isc_buffer_add(&b, strlen(argv[isc_commandline_index]));
319 	dns_fixedname_init(&fixed);
320 	dns_fixedname_init(&target);
321 	RUNTIME_CHECK(dns_name_fromtext(dns_fixedname_name(&fixed), &b,
322 					dns_rootname, 0,
323 					NULL) == ISC_R_SUCCESS);
324 
325 	RUNTIME_CHECK(isc_app_onrun(mctx, task, run, NULL) == ISC_R_SUCCESS);
326 
327 	(void)isc_app_run();
328 
329 	dns_view_detach(&view);
330 	isc_task_shutdown(task);
331 	isc_task_detach(&task);
332 
333 	dns_dispatchmgr_destroy(&dispatchmgr);
334 
335 	isc_managers_destroy(&netmgr, &taskmgr);
336 
337 	isc_socketmgr_destroy(&socketmgr);
338 	isc_timermgr_destroy(&timermgr);
339 
340 	isc_log_destroy(&lctx);
341 
342 	if (verbose) {
343 		isc_mem_stats(mctx, stdout);
344 	}
345 	isc_mem_destroy(&mctx);
346 
347 	isc_app_finish();
348 
349 	return (0);
350 }
351