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