aboutsummaryrefslogtreecommitdiff
path: root/src/dns/gnunet-zonewalk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/gnunet-zonewalk.c')
-rw-r--r--src/dns/gnunet-zonewalk.c609
1 files changed, 0 insertions, 609 deletions
diff --git a/src/dns/gnunet-zonewalk.c b/src/dns/gnunet-zonewalk.c
deleted file mode 100644
index 91f8456df..000000000
--- a/src/dns/gnunet-zonewalk.c
+++ /dev/null
@@ -1,609 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/dns/gnunet-zoneimport.c
23 * @brief import a DNS zone for analysis, brute force
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
28#include <gnunet_dnsstub_lib.h>
29#include <gnunet_dnsparser_lib.h>
30
31/**
32 * Request we should make.
33 */
34struct Request
35{
36 /**
37 * Requests are kept in a DLL.
38 */
39 struct Request *next;
40
41 /**
42 * Requests are kept in a DLL.
43 */
44 struct Request *prev;
45
46 /**
47 * Socket used to make the request, NULL if not active.
48 */
49 struct GNUNET_DNSSTUB_RequestSocket *rs;
50
51 /**
52 * Raw DNS query.
53 */
54 void *raw;
55
56 /**
57 * Number of bytes in @e raw.
58 */
59 size_t raw_len;
60
61 /**
62 * Hostname we are resolving.
63 */
64 char *hostname;
65
66 /**
67 * When did we last issue this request?
68 */
69 time_t time;
70
71 /**
72 * How often did we issue this query?
73 */
74 int issue_num;
75
76 /**
77 * random 16-bit DNS query identifier.
78 */
79 uint16_t id;
80};
81
82
83/**
84 * Context for DNS resolution.
85 */
86static struct GNUNET_DNSSTUB_Context *ctx;
87
88/**
89 * The number of queries that are outstanding
90 */
91static unsigned int pending;
92
93/**
94 * Number of lookups we performed overall.
95 */
96static unsigned int lookups;
97
98/**
99 * Number of lookups that failed.
100 */
101static unsigned int failures;
102
103/**
104 * Number of records we found.
105 */
106static unsigned int records;
107
108/**
109 * Head of DLL of all requests to perform.
110 */
111static struct Request *req_head;
112
113/**
114 * Tail of DLL of all requests to perform.
115 */
116static struct Request *req_tail;
117
118/**
119 * Main task.
120 */
121static struct GNUNET_SCHEDULER_Task *t;
122
123/**
124 * Maximum number of queries pending at the same time.
125 */
126#define THRESH 20
127
128/**
129 * TIME_THRESH is in usecs. How quickly do we submit fresh queries.
130 * Used as an additional throttle.
131 */
132#define TIME_THRESH 10
133
134/**
135 * How often do we retry a query before giving up for good?
136 */
137#define MAX_RETRIES 5
138
139
140/**
141 * We received @a rec for @a req. Remember the answer.
142 *
143 * @param req request
144 * @param rec response
145 */
146static void
147process_record (struct Request *req,
148 struct GNUNET_DNSPARSER_Record *rec)
149{
150 char buf[INET6_ADDRSTRLEN];
151
152 records++;
153 switch (rec->type)
154 {
155 case GNUNET_DNSPARSER_TYPE_A:
156 fprintf (stdout,
157 "%s A %s\n",
158 req->hostname,
159 inet_ntop (AF_INET,
160 rec->data.raw.data,
161 buf,
162 sizeof(buf)));
163 break;
164
165 case GNUNET_DNSPARSER_TYPE_AAAA:
166 fprintf (stdout,
167 "%s AAAA %s\n",
168 req->hostname,
169 inet_ntop (AF_INET6,
170 rec->data.raw.data,
171 buf,
172 sizeof(buf)));
173 break;
174
175 case GNUNET_DNSPARSER_TYPE_NS:
176 fprintf (stdout,
177 "%s NS %s\n",
178 req->hostname,
179 rec->data.hostname);
180 break;
181
182 case GNUNET_DNSPARSER_TYPE_CNAME:
183 fprintf (stdout,
184 "%s CNAME %s\n",
185 req->hostname,
186 rec->data.hostname);
187 break;
188
189 case GNUNET_DNSPARSER_TYPE_MX:
190 fprintf (stdout,
191 "%s MX %u %s\n",
192 req->hostname,
193 (unsigned int) rec->data.mx->preference,
194 rec->data.mx->mxhost);
195 break;
196
197 case GNUNET_DNSPARSER_TYPE_SOA:
198 fprintf (stdout,
199 "%s SOA %s %s %u %u %u %u %u\n",
200 req->hostname,
201 rec->data.soa->mname,
202 rec->data.soa->rname,
203 (unsigned int) rec->data.soa->serial,
204 (unsigned int) rec->data.soa->refresh,
205 (unsigned int) rec->data.soa->retry,
206 (unsigned int) rec->data.soa->expire,
207 (unsigned int) rec->data.soa->minimum_ttl);
208 break;
209
210 case GNUNET_DNSPARSER_TYPE_SRV:
211 fprintf (stdout,
212 "%s SRV %s %u %u %u\n",
213 req->hostname,
214 rec->data.srv->target,
215 rec->data.srv->priority,
216 rec->data.srv->weight,
217 rec->data.srv->port);
218 break;
219
220 case GNUNET_DNSPARSER_TYPE_PTR:
221 fprintf (stdout,
222 "%s PTR %s\n",
223 req->hostname,
224 rec->data.hostname);
225 break;
226
227 case GNUNET_DNSPARSER_TYPE_TXT:
228 fprintf (stdout,
229 "%s TXT %.*s\n",
230 req->hostname,
231 (int) rec->data.raw.data_len,
232 (char *) rec->data.raw.data);
233 break;
234
235 case GNUNET_DNSPARSER_TYPE_DNAME:
236 fprintf (stdout,
237 "%s DNAME %s\n",
238 req->hostname,
239 rec->data.hostname);
240 break;
241
242 /* obscure records */
243 case GNUNET_DNSPARSER_TYPE_AFSDB:
244 case GNUNET_DNSPARSER_TYPE_NAPTR:
245 case GNUNET_DNSPARSER_TYPE_APL:
246 case GNUNET_DNSPARSER_TYPE_DHCID:
247 case GNUNET_DNSPARSER_TYPE_HIP:
248 case GNUNET_DNSPARSER_TYPE_LOC:
249 case GNUNET_DNSPARSER_TYPE_RP:
250 case GNUNET_DNSPARSER_TYPE_TKEY:
251 case GNUNET_DNSPARSER_TYPE_TSIG:
252 case GNUNET_DNSPARSER_TYPE_URI:
253 case GNUNET_DNSPARSER_TYPE_TA:
254
255 /* DNSSEC */
256 case GNUNET_DNSPARSER_TYPE_DS:
257 case GNUNET_DNSPARSER_TYPE_RRSIG:
258 case GNUNET_DNSPARSER_TYPE_NSEC:
259 case GNUNET_DNSPARSER_TYPE_DNSKEY:
260 case GNUNET_DNSPARSER_TYPE_NSEC3:
261 case GNUNET_DNSPARSER_TYPE_NSEC3PARAM:
262 case GNUNET_DNSPARSER_TYPE_CDS:
263 case GNUNET_DNSPARSER_TYPE_CDNSKEY:
264
265 /* DNSSEC payload */
266 case GNUNET_DNSPARSER_TYPE_CERT:
267 case GNUNET_DNSPARSER_TYPE_SSHFP:
268 case GNUNET_DNSPARSER_TYPE_IPSECKEY:
269 case GNUNET_DNSPARSER_TYPE_TLSA:
270 case GNUNET_DNSPARSER_TYPE_OPENPGPKEY:
271
272 /* obsolete records */
273 case GNUNET_DNSPARSER_TYPE_SIG:
274 case GNUNET_DNSPARSER_TYPE_KEY:
275 case GNUNET_DNSPARSER_TYPE_KX:
276 {
277 char *base32;
278
279 base32 = GNUNET_STRINGS_data_to_string_alloc (rec->data.raw.data,
280 rec->data.raw.data_len);
281 fprintf (stdout,
282 "%s (%u) %s\n",
283 req->hostname,
284 rec->type,
285 base32);
286 GNUNET_free (base32);
287 }
288 break;
289
290 default:
291 fprintf (stderr,
292 "Unsupported type %u\n",
293 (unsigned int) rec->type);
294 break;
295 }
296}
297
298
299/**
300 * Function called with the result of a DNS resolution.
301 *
302 * @param cls closure with the `struct Request`
303 * @param dns dns response, never NULL
304 * @param dns_len number of bytes in @a dns
305 */
306static void
307process_result (void *cls,
308 const struct GNUNET_TUN_DnsHeader *dns,
309 size_t dns_len)
310{
311 struct Request *req = cls;
312 struct GNUNET_DNSPARSER_Packet *p;
313
314 if (NULL == dns)
315 {
316 /* stub gave up */
317 pending--;
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319 "Stub gave up on DNS reply for `%s'\n",
320 req->hostname);
321 GNUNET_CONTAINER_DLL_remove (req_head,
322 req_tail,
323 req);
324 if (req->issue_num > MAX_RETRIES)
325 {
326 failures++;
327 GNUNET_free (req->hostname);
328 GNUNET_free (req->raw);
329 GNUNET_free (req);
330 return;
331 }
332 GNUNET_CONTAINER_DLL_insert_tail (req_head,
333 req_tail,
334 req);
335 req->rs = NULL;
336 return;
337 }
338 if (req->id != dns->id)
339 return;
340 pending--;
341 GNUNET_DNSSTUB_resolve_cancel (req->rs);
342 req->rs = NULL;
343 GNUNET_CONTAINER_DLL_remove (req_head,
344 req_tail,
345 req);
346 p = GNUNET_DNSPARSER_parse ((const char *) dns,
347 dns_len);
348 if (NULL == p)
349 {
350 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
351 "Failed to parse DNS reply for `%s'\n",
352 req->hostname);
353 if (req->issue_num > MAX_RETRIES)
354 {
355 failures++;
356 GNUNET_free (req->hostname);
357 GNUNET_free (req->raw);
358 GNUNET_free (req);
359 return;
360 }
361 GNUNET_CONTAINER_DLL_insert_tail (req_head,
362 req_tail,
363 req);
364 return;
365 }
366 for (unsigned int i = 0; i < p->num_answers; i++)
367 {
368 struct GNUNET_DNSPARSER_Record *rs = &p->answers[i];
369
370 process_record (req,
371 rs);
372 }
373 for (unsigned int i = 0; i < p->num_authority_records; i++)
374 {
375 struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i];
376
377 process_record (req,
378 rs);
379 }
380 for (unsigned int i = 0; i < p->num_additional_records; i++)
381 {
382 struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i];
383
384 process_record (req,
385 rs);
386 }
387 GNUNET_DNSPARSER_free_packet (p);
388 GNUNET_free (req->hostname);
389 GNUNET_free (req->raw);
390 GNUNET_free (req);
391}
392
393
394/**
395 * Submit a request to DNS unless we need to slow down because
396 * we are at the rate limit.
397 *
398 * @param req request to submit
399 * @return #GNUNET_OK if request was submitted
400 * #GNUNET_NO if request was already submitted
401 * #GNUNET_SYSERR if we are at the rate limit
402 */
403static int
404submit_req (struct Request *req)
405{
406 static struct timeval last_request;
407 struct timeval now;
408
409 if (NULL != req->rs)
410 return GNUNET_NO; /* already submitted */
411 gettimeofday (&now,
412 NULL);
413 if ((((now.tv_sec - last_request.tv_sec) == 0) &&
414 ((now.tv_usec - last_request.tv_usec) < TIME_THRESH)) ||
415 (pending >= THRESH))
416 return GNUNET_SYSERR;
417 GNUNET_assert (NULL == req->rs);
418 req->rs = GNUNET_DNSSTUB_resolve (ctx,
419 req->raw,
420 req->raw_len,
421 &process_result,
422 req);
423 GNUNET_assert (NULL != req->rs);
424 req->issue_num++;
425 last_request = now;
426 lookups++;
427 pending++;
428 req->time = time (NULL);
429 return GNUNET_OK;
430}
431
432
433/**
434 * Process as many requests as possible from the queue.
435 *
436 * @param cls NULL
437 */
438static void
439process_queue (void *cls)
440{
441 (void) cls;
442 t = NULL;
443 for (struct Request *req = req_head;
444 NULL != req;
445 req = req->next)
446 {
447 if (GNUNET_SYSERR == submit_req (req))
448 break;
449 }
450 if (NULL != req_head)
451 t = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
452 &process_queue,
453 NULL);
454 else
455 GNUNET_SCHEDULER_shutdown ();
456}
457
458
459/**
460 * Clean up and terminate the process.
461 *
462 * @param cls NULL
463 */
464static void
465do_shutdown (void *cls)
466{
467 (void) cls;
468 if (NULL != t)
469 {
470 GNUNET_SCHEDULER_cancel (t);
471 t = NULL;
472 }
473 GNUNET_DNSSTUB_stop (ctx);
474 ctx = NULL;
475}
476
477
478/**
479 * Process requests from the queue, then if the queue is
480 * not empty, try again.
481 *
482 * @param cls NULL
483 */
484static void
485run (void *cls)
486{
487 (void) cls;
488
489 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
490 NULL);
491 t = GNUNET_SCHEDULER_add_now (&process_queue,
492 NULL);
493}
494
495
496/**
497 * Add @a hostname to the list of requests to be made.
498 *
499 * @param hostname name to resolve
500 */
501static void
502queue (const char *hostname)
503{
504 struct GNUNET_DNSPARSER_Packet p;
505 struct GNUNET_DNSPARSER_Query q;
506 struct Request *req;
507 char *raw;
508 size_t raw_size;
509 int ret;
510
511 if (GNUNET_OK !=
512 GNUNET_DNSPARSER_check_name (hostname))
513 {
514 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
515 "Refusing invalid hostname `%s'\n",
516 hostname);
517 return;
518 }
519 q.name = (char *) hostname;
520 q.type = GNUNET_DNSPARSER_TYPE_NS;
521 q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
522
523 memset (&p,
524 0,
525 sizeof(p));
526 p.num_queries = 1;
527 p.queries = &q;
528 p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
529 UINT16_MAX);
530 ret = GNUNET_DNSPARSER_pack (&p,
531 UINT16_MAX,
532 &raw,
533 &raw_size);
534 if (GNUNET_OK != ret)
535 {
536 if (GNUNET_NO == ret)
537 GNUNET_free (raw);
538 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
539 "Failed to pack query for hostname `%s'\n",
540 hostname);
541 return;
542 }
543
544 req = GNUNET_new (struct Request);
545 req->hostname = strdup (hostname);
546 req->raw = raw;
547 req->raw_len = raw_size;
548 req->id = p.id;
549 GNUNET_CONTAINER_DLL_insert_tail (req_head,
550 req_tail,
551 req);
552}
553
554
555/**
556 * Call with IP address of resolver to query.
557 *
558 * @param argc should be 2
559 * @param argv[1] should contain IP address
560 * @return 0 on success
561 */
562int
563main (int argc,
564 char **argv)
565{
566 char hn[256];
567
568 if (2 != argc)
569 {
570 fprintf (stderr,
571 "Missing required configuration argument\n");
572 return -1;
573 }
574 ctx = GNUNET_DNSSTUB_start (256);
575 if (NULL == ctx)
576 {
577 fprintf (stderr,
578 "Failed to initialize GNUnet DNS STUB\n");
579 return 1;
580 }
581 if (GNUNET_OK !=
582 GNUNET_DNSSTUB_add_dns_ip (ctx,
583 argv[1]))
584 {
585 fprintf (stderr,
586 "Failed to use `%s' for DNS resolver\n",
587 argv[1]);
588 return 1;
589 }
590
591 while (NULL !=
592 fgets (hn,
593 sizeof(hn),
594 stdin))
595 {
596 if (strlen (hn) > 0)
597 hn[strlen (hn) - 1] = '\0'; /* eat newline */
598 queue (hn);
599 }
600 GNUNET_SCHEDULER_run (&run,
601 NULL);
602 fprintf (stderr,
603 "Did %u lookups, found %u records, %u lookups failed, %u pending on shutdown\n",
604 lookups,
605 records,
606 failures,
607 pending);
608 return 0;
609}