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 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17
18 #include <isc/app.h>
19 #include <isc/base64.h>
20 #include <isc/log.h>
21 #include <isc/managers.h>
22 #include <isc/mem.h>
23 #include <isc/print.h>
24 #include <isc/sockaddr.h>
25 #include <isc/socket.h>
26 #include <isc/task.h>
27 #include <isc/timer.h>
28 #include <isc/util.h>
29
30 #include <dns/dispatch.h>
31 #include <dns/dnssec.h>
32 #include <dns/events.h>
33 #include <dns/fixedname.h>
34 #include <dns/keyvalues.h>
35 #include <dns/log.h>
36 #include <dns/masterdump.h>
37 #include <dns/message.h>
38 #include <dns/name.h>
39 #include <dns/rdataset.h>
40 #include <dns/request.h>
41 #include <dns/resolver.h>
42 #include <dns/result.h>
43 #include <dns/tkey.h>
44 #include <dns/tsig.h>
45 #include <dns/types.h>
46 #include <dns/view.h>
47
48 #include <dst/result.h>
49
50 #ifdef GSSAPI
51 #include ISC_PLATFORM_GSSAPIHEADER
52
53 #define CHECK(str, x) \
54 { \
55 if ((x) != ISC_R_SUCCESS) { \
56 fprintf(stderr, "I:%d:%s: %s\n", __LINE__, (str), \
57 isc_result_totext(x)); \
58 goto end; \
59 } \
60 }
61
62 static dns_fixedname_t servername, gssname;
63
64 static isc_mem_t *mctx = NULL;
65 static dns_requestmgr_t *requestmgr = NULL;
66 static isc_sockaddr_t address;
67
68 static dns_tsig_keyring_t *ring = NULL;
69 static dns_tsigkey_t *tsigkey = NULL;
70 static dns_gss_ctx_id_t gssctx;
71 static dns_gss_ctx_id_t *gssctxp = &gssctx;
72
73 #define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
74
75 #define PORT 53
76 #define TIMEOUT 30
77
78 static void
79 initctx1(isc_task_t *task, isc_event_t *event);
80 static void
81 sendquery(isc_task_t *task, isc_event_t *event);
82 static void
83 setup();
84
85 static void
console(isc_task_t * task,isc_event_t * event)86 console(isc_task_t *task, isc_event_t *event) {
87 char buf[32];
88 int c;
89
90 isc_event_t *ev = NULL;
91
92 isc_event_free(&event);
93
94 for (;;) {
95 printf("\nCommand => ");
96 c = scanf("%31s", buf);
97
98 if (c == EOF || strcmp(buf, "quit") == 0) {
99 isc_app_shutdown();
100 return;
101 }
102
103 if (strcmp(buf, "initctx") == 0) {
104 ev = isc_event_allocate(mctx, (void *)1, 1, initctx1,
105 NULL, sizeof(*event));
106 isc_task_send(task, &ev);
107 return;
108 }
109
110 if (strcmp(buf, "query") == 0) {
111 ev = isc_event_allocate(mctx, (void *)1, 1, sendquery,
112 NULL, sizeof(*event));
113 isc_task_send(task, &ev);
114 return;
115 }
116
117 printf("Unknown command\n");
118 }
119 }
120
121 static void
recvresponse(isc_task_t * task,isc_event_t * event)122 recvresponse(isc_task_t *task, isc_event_t *event) {
123 dns_requestevent_t *reqev = (dns_requestevent_t *)event;
124 isc_result_t result, result2;
125 dns_message_t *query = NULL, *response = NULL;
126 isc_buffer_t outtoken;
127 isc_buffer_t outbuf;
128 char output[10 * 1024];
129
130 unsigned char array[DNS_NAME_MAXTEXT + 1];
131 isc_buffer_init(&outtoken, array, sizeof(array));
132
133 UNUSED(task);
134
135 REQUIRE(reqev != NULL);
136
137 query = reqev->ev_arg;
138
139 if (reqev->result != ISC_R_SUCCESS) {
140 fprintf(stderr, "I:request event result: %s\n",
141 isc_result_totext(reqev->result));
142 goto end;
143 }
144
145 response = NULL;
146 dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
147
148 printf("\nReceived Response:\n");
149
150 result2 = dns_request_getresponse(reqev->request, response,
151 DNS_MESSAGEPARSE_PRESERVEORDER);
152 isc_buffer_init(&outbuf, output, sizeof(output));
153 result = dns_message_totext(response, &dns_master_style_debug, 0,
154 &outbuf);
155 CHECK("dns_message_totext", result);
156 printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
157 (char *)isc_buffer_base(&outbuf));
158
159 CHECK("dns_request_getresponse", result2);
160
161 if (response != NULL) {
162 dns_message_detach(&response);
163 }
164
165 end:
166 if (query != NULL) {
167 dns_message_detach(&query);
168 }
169
170 if (reqev->request != NULL) {
171 dns_request_destroy(&reqev->request);
172 }
173
174 isc_event_free(&event);
175
176 event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
177 sizeof(*event));
178 isc_task_send(task, &event);
179 return;
180 }
181
182 static void
sendquery(isc_task_t * task,isc_event_t * event)183 sendquery(isc_task_t *task, isc_event_t *event) {
184 dns_request_t *request = NULL;
185 dns_message_t *message = NULL;
186 dns_name_t *qname = NULL;
187 dns_rdataset_t *qrdataset = NULL;
188 isc_result_t result;
189 dns_fixedname_t queryname;
190 isc_buffer_t buf;
191 isc_buffer_t outbuf;
192 char output[10 * 1024];
193 static char host[256];
194 int c;
195
196 isc_event_free(&event);
197
198 printf("Query => ");
199 c = scanf("%255s", host);
200 if (c == EOF) {
201 return;
202 }
203
204 dns_fixedname_init(&queryname);
205 isc_buffer_init(&buf, host, strlen(host));
206 isc_buffer_add(&buf, strlen(host));
207 result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
208 dns_rootname, 0, NULL);
209 CHECK("dns_name_fromtext", result);
210
211 dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
212
213 message->opcode = dns_opcode_query;
214 message->rdclass = dns_rdataclass_in;
215 message->id = (unsigned short)(random() & 0xFFFF);
216
217 result = dns_message_gettempname(message, &qname);
218 if (result != ISC_R_SUCCESS) {
219 goto end;
220 }
221
222 result = dns_message_gettemprdataset(message, &qrdataset);
223 if (result != ISC_R_SUCCESS) {
224 goto end;
225 }
226
227 dns_name_init(qname, NULL);
228 dns_name_clone(dns_fixedname_name(&queryname), qname);
229 dns_rdataset_makequestion(qrdataset, dns_rdataclass_in,
230 dns_rdatatype_a);
231 ISC_LIST_APPEND(qname->list, qrdataset, link);
232 dns_message_addname(message, qname, DNS_SECTION_QUESTION);
233
234 result = dns_request_create(requestmgr, message, &address, 0, tsigkey,
235 TIMEOUT, task, recvresponse, message,
236 &request);
237 CHECK("dns_request_create", result);
238
239 printf("Submitting query:\n");
240 isc_buffer_init(&outbuf, output, sizeof(output));
241 result = dns_message_totext(message, &dns_master_style_debug, 0,
242 &outbuf);
243 CHECK("dns_message_totext", result);
244 printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
245 (char *)isc_buffer_base(&outbuf));
246
247 return;
248
249 end:
250 if (qname != NULL) {
251 dns_message_puttempname(message, &qname);
252 }
253 if (qrdataset != NULL) {
254 dns_message_puttemprdataset(message, &qrdataset);
255 }
256 if (message != NULL) {
257 dns_message_detach(&message);
258 }
259 }
260
261 static void
initctx2(isc_task_t * task,isc_event_t * event)262 initctx2(isc_task_t *task, isc_event_t *event) {
263 dns_requestevent_t *reqev = (dns_requestevent_t *)event;
264 isc_result_t result;
265 dns_message_t *query = NULL, *response = NULL;
266 isc_buffer_t outtoken;
267 unsigned char array[DNS_NAME_MAXTEXT + 1];
268 dns_rdataset_t *rdataset;
269 dns_rdatatype_t qtype;
270 dns_name_t *question_name;
271
272 UNUSED(task);
273
274 REQUIRE(reqev != NULL);
275
276 query = reqev->ev_arg;
277
278 if (reqev->result != ISC_R_SUCCESS) {
279 fprintf(stderr, "I:request event result: %s\n",
280 isc_result_totext(reqev->result));
281 goto end;
282 }
283
284 response = NULL;
285 dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
286
287 result = dns_request_getresponse(reqev->request, response,
288 DNS_MESSAGEPARSE_PRESERVEORDER);
289 CHECK("dns_request_getresponse", result);
290
291 if (response->rcode != dns_rcode_noerror) {
292 result = ISC_RESULTCLASS_DNSRCODE + response->rcode;
293 fprintf(stderr, "I:response rcode: %s\n",
294 isc_result_totext(result));
295 goto end;
296 }
297
298 printf("Received token from server, calling gss_init_sec_context()\n");
299 isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1);
300 result = dns_tkey_processgssresponse(
301 query, response, dns_fixedname_name(&gssname), &gssctx,
302 &outtoken, &tsigkey, ring, NULL);
303 gssctx = *gssctxp;
304 CHECK("dns_tkey_processgssresponse", result);
305 printf("Context accepted\n");
306
307 question_name = NULL;
308 dns_message_currentname(response, DNS_SECTION_ANSWER, &question_name);
309 rdataset = ISC_LIST_HEAD(question_name->list);
310 INSIST(rdataset != NULL);
311 qtype = rdataset->type;
312 if (qtype == dns_rdatatype_tkey) {
313 printf("Received TKEY response from server\n");
314 printf("Context completed\n");
315 } else {
316 printf("Did not receive TKEY response from server\n");
317 printf("Context not completed\n");
318 dns_tsigkey_detach(&tsigkey);
319 tsigkey = NULL;
320 }
321
322 dns_message_detach(&response);
323
324 end:
325 if (query != NULL) {
326 dns_message_detach(&query);
327 }
328
329 if (reqev->request != NULL) {
330 dns_request_destroy(&reqev->request);
331 }
332
333 isc_event_free(&event);
334
335 event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
336 sizeof(*event));
337 isc_task_send(task, &event);
338 return;
339 }
340
341 static void
initctx1(isc_task_t * task,isc_event_t * event)342 initctx1(isc_task_t *task, isc_event_t *event) {
343 char gssid[512];
344 char contextname[512];
345 isc_result_t result;
346 isc_buffer_t buf;
347 dns_message_t *query;
348 dns_request_t *request;
349 int c;
350
351 isc_event_free(&event);
352
353 printf("Initctx - GSS name => ");
354 c = scanf("%511s", gssid);
355 if (c == EOF) {
356 return;
357 }
358
359 snprintf(contextname, sizeof(contextname), "gsstest.context.%d.",
360 (int)time(NULL));
361
362 printf("Initctx - context name we're using: %s\n", contextname);
363
364 printf("Negotiating GSSAPI context: ");
365 printf("%s", gssid);
366 printf("\n");
367
368 /*
369 * Setup a GSSAPI context with the server
370 */
371 dns_fixedname_init(&servername);
372 isc_buffer_init(&buf, contextname, strlen(contextname));
373 isc_buffer_add(&buf, strlen(contextname));
374 result = dns_name_fromtext(dns_fixedname_name(&servername), &buf,
375 dns_rootname, 0, NULL);
376 CHECK("dns_name_fromtext", result);
377
378 /* Make name happen */
379 dns_fixedname_init(&gssname);
380 isc_buffer_init(&buf, gssid, strlen(gssid));
381 isc_buffer_add(&buf, strlen(gssid));
382 result = dns_name_fromtext(dns_fixedname_name(&gssname), &buf,
383 dns_rootname, 0, NULL);
384 CHECK("dns_name_fromtext", result);
385
386 query = NULL;
387 dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
388
389 printf("Calling gss_init_sec_context()\n");
390 gssctx = GSS_C_NO_CONTEXT;
391 result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername),
392 dns_fixedname_name(&gssname), NULL,
393 36000, &gssctx, true, mctx, NULL);
394 CHECK("dns_tkey_buildgssquery", result);
395
396 printf("Sending context token to server\n");
397 request = NULL;
398 result = dns_request_create(requestmgr, query, &address, 0, NULL,
399 TIMEOUT, task, initctx2, query, &request);
400 CHECK("dns_request_create", result);
401
402 return;
403 end:
404 event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
405 sizeof(*event));
406 isc_task_send(task, &event);
407 return;
408 }
409
410 static void
setup(void)411 setup(void) {
412 for (;;) {
413 char serveraddress[512];
414 struct in_addr inaddr;
415 int c;
416
417 printf("Server IP => ");
418 c = scanf("%511s", serveraddress);
419
420 if (c == EOF || strcmp(serveraddress, "quit") == 0) {
421 isc_app_shutdown();
422 return;
423 }
424
425 if (inet_pton(AF_INET, serveraddress, &inaddr) == 1) {
426 isc_sockaddr_fromin(&address, &inaddr, PORT);
427 return;
428 }
429 }
430 }
431
432 int
main(int argc,char * argv[])433 main(int argc, char *argv[]) {
434 isc_nm_t *netmgr = NULL;
435 isc_taskmgr_t *taskmgr = NULL;
436 isc_timermgr_t *timermgr = NULL;
437 isc_socketmgr_t *socketmgr = NULL;
438 isc_socket_t *sock = NULL;
439 unsigned int attrs, attrmask;
440 isc_sockaddr_t bind_any;
441 dns_dispatchmgr_t *dispatchmgr = NULL;
442 dns_dispatch_t *dispatchv4 = NULL;
443 dns_view_t *view = NULL;
444 isc_task_t *task = NULL;
445 isc_log_t *lctx = NULL;
446 isc_logconfig_t *lcfg = NULL;
447 isc_logdestination_t destination;
448
449 UNUSED(argv);
450 UNUSED(argc);
451
452 RUNCHECK(isc_app_start());
453
454 dns_result_register();
455
456 mctx = NULL;
457 isc_mem_create(&mctx);
458
459 isc_log_create(mctx, &lctx, &lcfg);
460 isc_log_setcontext(lctx);
461 dns_log_init(lctx);
462 dns_log_setcontext(lctx);
463
464 /*
465 * Create and install the default channel.
466 */
467 destination.file.stream = stderr;
468 destination.file.name = NULL;
469 destination.file.versions = ISC_LOG_ROLLNEVER;
470 destination.file.maximum_size = 0;
471 isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC,
472 ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME);
473
474 RUNCHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL));
475
476 isc_log_setdebuglevel(lctx, 9);
477
478 RUNCHECK(dst_lib_init(mctx, NULL));
479
480 RUNCHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr));
481 RUNCHECK(isc_task_create(taskmgr, 0, &task));
482 RUNCHECK(isc_timermgr_create(mctx, &timermgr));
483 RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
484 RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr));
485 isc_sockaddr_any(&bind_any);
486 attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY |
487 DNS_DISPATCHATTR_IPV4;
488 attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP |
489 DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
490 RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any,
491 4096, 4, 2, 3, 5, attrs, attrmask,
492 &dispatchv4));
493 RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
494 dispatchmgr, dispatchv4, NULL,
495 &requestmgr));
496
497 RUNCHECK(dns_tsigkeyring_create(mctx, &ring));
498
499 RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
500 dns_view_setkeyring(view, ring);
501
502 RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp,
503 &sock));
504
505 setup();
506
507 RUNCHECK(isc_app_onrun(mctx, task, console, NULL));
508
509 (void)isc_app_run();
510
511 if (tsigkey) {
512 dns_tsigkey_detach(&tsigkey);
513 }
514
515 dns_requestmgr_shutdown(requestmgr);
516 dns_requestmgr_detach(&requestmgr);
517
518 dns_dispatch_detach(&dispatchv4);
519 dns_dispatchmgr_destroy(&dispatchmgr);
520
521 isc_timermgr_destroy(&timermgr);
522
523 isc_task_detach(&task);
524 isc_managers_destroy(&netmgr, &taskmgr);
525
526 isc_socket_detach(&sock);
527 isc_socketmgr_destroy(&socketmgr);
528
529 isc_mem_stats(mctx, stdout);
530
531 dns_view_detach(&view);
532
533 dst_lib_destroy();
534
535 isc_mem_stats(mctx, stdout);
536 isc_mem_destroy(&mctx);
537
538 isc_app_finish();
539
540 return (0);
541 }
542 #else /* ifdef GSSAPI */
543 int
main(int argc,char * argv[])544 main(int argc, char *argv[]) {
545 UNUSED(argc);
546 UNUSED(argv);
547 fprintf(stderr, "R:GSSAPIONLY\n");
548 return (0);
549 }
550 #endif /* ifdef GSSAPI */
551