GNUnet 0.21.1
gnunet-zonewalk.c
Go to the documentation of this file.
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
26#include "platform.h"
27#include <gnunet_util_lib.h>
28
32struct Request
33{
37 struct Request *next;
38
42 struct Request *prev;
43
48
52 void *raw;
53
57 size_t raw_len;
58
62 char *hostname;
63
67 time_t time;
68
73
77 uint16_t id;
78};
79
80
85
89static unsigned int pending;
90
94static unsigned int lookups;
95
99static unsigned int failures;
100
104static unsigned int records;
105
109static struct Request *req_head;
110
114static struct Request *req_tail;
115
120
124#define THRESH 20
125
130#define TIME_THRESH 10
131
135#define MAX_RETRIES 5
136
137
144static void
146 struct GNUNET_DNSPARSER_Record *rec)
147{
148 char buf[INET6_ADDRSTRLEN];
149
150 records++;
151 switch (rec->type)
152 {
154 fprintf (stdout,
155 "%s A %s\n",
156 req->hostname,
157 inet_ntop (AF_INET,
158 rec->data.raw.data,
159 buf,
160 sizeof(buf)));
161 break;
162
164 fprintf (stdout,
165 "%s AAAA %s\n",
166 req->hostname,
167 inet_ntop (AF_INET6,
168 rec->data.raw.data,
169 buf,
170 sizeof(buf)));
171 break;
172
174 fprintf (stdout,
175 "%s NS %s\n",
176 req->hostname,
177 rec->data.hostname);
178 break;
179
181 fprintf (stdout,
182 "%s CNAME %s\n",
183 req->hostname,
184 rec->data.hostname);
185 break;
186
188 fprintf (stdout,
189 "%s MX %u %s\n",
190 req->hostname,
191 (unsigned int) rec->data.mx->preference,
192 rec->data.mx->mxhost);
193 break;
194
196 fprintf (stdout,
197 "%s SOA %s %s %u %u %u %u %u\n",
198 req->hostname,
199 rec->data.soa->mname,
200 rec->data.soa->rname,
201 (unsigned int) rec->data.soa->serial,
202 (unsigned int) rec->data.soa->refresh,
203 (unsigned int) rec->data.soa->retry,
204 (unsigned int) rec->data.soa->expire,
205 (unsigned int) rec->data.soa->minimum_ttl);
206 break;
207
209 fprintf (stdout,
210 "%s SRV %s %u %u %u\n",
211 req->hostname,
212 rec->data.srv->target,
213 rec->data.srv->priority,
214 rec->data.srv->weight,
215 rec->data.srv->port);
216 break;
217
219 fprintf (stdout,
220 "%s URI \"%s\" %u %u\n",
221 req->hostname,
222 rec->data.uri->target,
223 rec->data.uri->priority,
224 rec->data.uri->weight);
225 break;
226
228 fprintf (stdout,
229 "%s PTR %s\n",
230 req->hostname,
231 rec->data.hostname);
232 break;
233
235 fprintf (stdout,
236 "%s TXT %.*s\n",
237 req->hostname,
238 (int) rec->data.raw.data_len,
239 (char *) rec->data.raw.data);
240 break;
241
243 fprintf (stdout,
244 "%s DNAME %s\n",
245 req->hostname,
246 rec->data.hostname);
247 break;
248
249 /* obscure records */
260
261 /* DNSSEC */
270
271 /* DNSSEC payload */
278
279 /* obsolete records */
283 {
284 char *base32;
285
287 rec->data.raw.data_len);
288 fprintf (stdout,
289 "%s (%u) %s\n",
290 req->hostname,
291 rec->type,
292 base32);
293 GNUNET_free (base32);
294 }
295 break;
296
297 default:
298 fprintf (stderr,
299 "Unsupported type %u\n",
300 (unsigned int) rec->type);
301 break;
302 }
303}
304
305
313static void
314process_result (void *cls,
315 const struct GNUNET_TUN_DnsHeader *dns,
316 size_t dns_len)
317{
318 struct Request *req = cls;
320
321 if (NULL == dns)
322 {
323 /* stub gave up */
324 pending--;
326 "Stub gave up on DNS reply for `%s'\n",
327 req->hostname);
329 req_tail,
330 req);
331 if (req->issue_num > MAX_RETRIES)
332 {
333 failures++;
334 GNUNET_free (req->hostname);
335 GNUNET_free (req->raw);
336 GNUNET_free (req);
337 return;
338 }
340 req_tail,
341 req);
342 req->rs = NULL;
343 return;
344 }
345 if (req->id != dns->id)
346 return;
347 pending--;
349 req->rs = NULL;
351 req_tail,
352 req);
353 p = GNUNET_DNSPARSER_parse ((const char *) dns,
354 dns_len);
355 if (NULL == p)
356 {
358 "Failed to parse DNS reply for `%s'\n",
359 req->hostname);
360 if (req->issue_num > MAX_RETRIES)
361 {
362 failures++;
363 GNUNET_free (req->hostname);
364 GNUNET_free (req->raw);
365 GNUNET_free (req);
366 return;
367 }
369 req_tail,
370 req);
371 return;
372 }
373 for (unsigned int i = 0; i < p->num_answers; i++)
374 {
375 struct GNUNET_DNSPARSER_Record *rs = &p->answers[i];
376
377 process_record (req,
378 rs);
379 }
380 for (unsigned int i = 0; i < p->num_authority_records; i++)
381 {
382 struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i];
383
384 process_record (req,
385 rs);
386 }
387 for (unsigned int i = 0; i < p->num_additional_records; i++)
388 {
389 struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i];
390
391 process_record (req,
392 rs);
393 }
395 GNUNET_free (req->hostname);
396 GNUNET_free (req->raw);
397 GNUNET_free (req);
398}
399
400
410static int
411submit_req (struct Request *req)
412{
413 static struct timeval last_request;
414 struct timeval now;
415
416 if (NULL != req->rs)
417 return GNUNET_NO; /* already submitted */
418 gettimeofday (&now,
419 NULL);
420 if ((((now.tv_sec - last_request.tv_sec) == 0) &&
421 ((now.tv_usec - last_request.tv_usec) < TIME_THRESH)) ||
422 (pending >= THRESH))
423 return GNUNET_SYSERR;
424 GNUNET_assert (NULL == req->rs);
426 req->raw,
427 req->raw_len,
429 req);
430 GNUNET_assert (NULL != req->rs);
431 req->issue_num++;
432 last_request = now;
433 lookups++;
434 pending++;
435 req->time = time (NULL);
436 return GNUNET_OK;
437}
438
439
445static void
446process_queue (void *cls)
447{
448 (void) cls;
449 t = NULL;
450 for (struct Request *req = req_head;
451 NULL != req;
452 req = req->next)
453 {
454 if (GNUNET_SYSERR == submit_req (req))
455 break;
456 }
457 if (NULL != req_head)
460 NULL);
461 else
463}
464
465
471static void
472do_shutdown (void *cls)
473{
474 (void) cls;
475 if (NULL != t)
476 {
478 t = NULL;
479 }
481 ctx = NULL;
482}
483
484
491static void
492run (void *cls)
493{
494 (void) cls;
495
497 NULL);
499 NULL);
500}
501
502
508static void
509queue (const char *hostname)
510{
513 struct Request *req;
514 char *raw;
515 size_t raw_size;
516 int ret;
517
518 if (GNUNET_OK !=
520 {
522 "Refusing invalid hostname `%s'\n",
523 hostname);
524 return;
525 }
526 q.name = (char *) hostname;
528 q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
529
530 memset (&p,
531 0,
532 sizeof(p));
533 p.num_queries = 1;
534 p.queries = &q;
536 UINT16_MAX);
538 UINT16_MAX,
539 &raw,
540 &raw_size);
541 if (GNUNET_OK != ret)
542 {
543 if (GNUNET_NO == ret)
546 "Failed to pack query for hostname `%s'\n",
547 hostname);
548 return;
549 }
550
551 req = GNUNET_new (struct Request);
552 req->hostname = strdup (hostname);
553 req->raw = raw;
554 req->raw_len = raw_size;
555 req->id = p.id;
557 req_tail,
558 req);
559}
560
561
569int
570main (int argc,
571 char **argv)
572{
573 char hn[256];
574
575 if (2 != argc)
576 {
577 fprintf (stderr,
578 "Missing required configuration argument\n");
579 return -1;
580 }
582 if (NULL == ctx)
583 {
584 fprintf (stderr,
585 "Failed to initialize GNUnet DNS STUB\n");
586 return 1;
587 }
588 if (GNUNET_OK !=
590 argv[1]))
591 {
592 fprintf (stderr,
593 "Failed to use `%s' for DNS resolver\n",
594 argv[1]);
595 return 1;
596 }
597
598 while (NULL !=
599 fgets (hn,
600 sizeof(hn),
601 stdin))
602 {
603 if (strlen (hn) > 0)
604 hn[strlen (hn) - 1] = '\0'; /* eat newline */
605 queue (hn);
606 }
608 NULL);
609 fprintf (stderr,
610 "Did %u lookups, found %u records, %u lookups failed, %u pending on shutdown\n",
611 lookups,
612 records,
613 failures,
614 pending);
615 return 0;
616}
static int ret
Final status code.
Definition: gnunet-arm.c:94
static int raw
raw output
Definition: gnunet-gns.c:78
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
#define THRESH
Maximum number of queries pending at the same time.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
static unsigned int records
Number of records we found.
static void process_queue(void *cls)
Process as many requests as possible from the queue.
int main(int argc, char **argv)
Call with IP address of resolver to query.
static void queue(const char *hostname)
Add hostname to the list of requests to be made.
static unsigned int pending
The number of queries that are outstanding.
static struct GNUNET_SCHEDULER_Task * t
Main task.
static void run(void *cls)
Process requests from the queue, then if the queue is not empty, try again.
static void do_shutdown(void *cls)
Clean up and terminate the process.
static int submit_req(struct Request *req)
Submit a request to DNS unless we need to slow down because we are at the rate limit.
static unsigned int lookups
Number of lookups we performed overall.
static void process_result(void *cls, const struct GNUNET_TUN_DnsHeader *dns, size_t dns_len)
Function called with the result of a DNS resolution.
static struct Request * req_tail
Tail of DLL of all requests to perform.
static struct Request * req_head
Head of DLL of all requests to perform.
#define MAX_RETRIES
How often do we retry a query before giving up for good?
#define TIME_THRESH
TIME_THRESH is in usecs.
static unsigned int failures
Number of lookups that failed.
static void process_record(struct Request *req, struct GNUNET_DNSPARSER_Record *rec)
We received rec for req.
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
@ GNUNET_CRYPTO_QUALITY_NONCE
Randomness for IVs etc.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_DNSPARSER_TYPE_RRSIG
#define GNUNET_DNSPARSER_TYPE_SIG
#define GNUNET_DNSPARSER_TYPE_TKEY
#define GNUNET_DNSPARSER_TYPE_URI
#define GNUNET_DNSPARSER_TYPE_OPENPGPKEY
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:947
#define GNUNET_DNSPARSER_TYPE_TA
#define GNUNET_DNSPARSER_TYPE_IPSECKEY
#define GNUNET_DNSPARSER_TYPE_TLSA
#define GNUNET_DNSPARSER_TYPE_DHCID
#define GNUNET_DNSPARSER_TYPE_NSEC3
#define GNUNET_DNSPARSER_TYPE_SRV
#define GNUNET_DNSPARSER_TYPE_SSHFP
#define GNUNET_DNSPARSER_TYPE_SOA
#define GNUNET_DNSPARSER_TYPE_CERT
#define GNUNET_DNSPARSER_TYPE_A
#define GNUNET_DNSPARSER_TYPE_NSEC3PARAM
#define GNUNET_DNSPARSER_TYPE_SMIMEA
#define GNUNET_DNSPARSER_TYPE_NSEC
#define GNUNET_DNSPARSER_TYPE_DS
#define GNUNET_DNSPARSER_TYPE_PTR
#define GNUNET_DNSPARSER_TYPE_HIP
int GNUNET_DNSPARSER_check_name(const char *name)
Check if a hostname in UTF-8 format can be coded into valid IDNA.
Definition: dnsparser.c:79
#define GNUNET_DNSPARSER_TYPE_DNSKEY
#define GNUNET_DNSPARSER_TYPE_TSIG
#define GNUNET_DNSPARSER_TYPE_NS
#define GNUNET_DNSPARSER_TYPE_NAPTR
#define GNUNET_DNSPARSER_TYPE_CNAME
#define GNUNET_DNSPARSER_TYPE_DNAME
#define GNUNET_DNSPARSER_TYPE_LOC
#define GNUNET_DNSPARSER_TYPE_RP
#define GNUNET_DNSPARSER_TYPE_CDS
#define GNUNET_DNSPARSER_TYPE_APL
#define GNUNET_DNSPARSER_TYPE_AAAA
#define GNUNET_DNSPARSER_TYPE_AFSDB
int GNUNET_DNSPARSER_pack(const struct GNUNET_DNSPARSER_Packet *p, uint16_t max, char **buf, size_t *buf_length)
Given a DNS packet p, generate the corresponding UDP payload.
Definition: dnsparser.c:1392
#define GNUNET_DNSPARSER_TYPE_KEY
#define GNUNET_DNSPARSER_TYPE_KX
#define GNUNET_DNSPARSER_TYPE_MX
#define GNUNET_DNSPARSER_TYPE_TXT
#define GNUNET_DNSPARSER_TYPE_CDNSKEY
struct GNUNET_DNSPARSER_Packet * GNUNET_DNSPARSER_parse(const char *udp_payload, size_t udp_payload_length)
Parse a UDP payload of a DNS packet in to a nice struct for further processing and manipulation.
Definition: dnsparser.c:727
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:586
int GNUNET_DNSSTUB_add_dns_ip(struct GNUNET_DNSSTUB_Context *ctx, const char *dns_ip)
Add nameserver for use by the DNSSTUB.
Definition: dnsstub.c:613
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition: dnsstub.c:705
struct GNUNET_DNSSTUB_RequestSocket * GNUNET_DNSSTUB_resolve(struct GNUNET_DNSSTUB_Context *ctx, const void *request, size_t request_len, GNUNET_DNSSTUB_ResultCallback rc, void *rc_cls)
Perform DNS resolution using our default IP from init.
Definition: dnsstub.c:526
void GNUNET_DNSSTUB_resolve_cancel(struct GNUNET_DNSSTUB_RequestSocket *rs)
Cancel DNS resolution.
Definition: dnsstub.c:562
#define GNUNET_log(kind,...)
@ GNUNET_OK
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_ERROR
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:567
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:725
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1340
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1305
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1278
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:764
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
#define GNUNET_TUN_DNS_CLASS_INTERNET
A few common DNS classes (ok, only one is common, but I list a couple more to make it clear what we'r...
char * mxhost
Name of the mail server.
uint16_t preference
Preference for this entry (lower value is higher preference).
Easy-to-process, parsed version of a DNS packet.
void * data
Binary record data.
size_t data_len
Number of bytes in data.
A DNS response record.
struct GNUNET_DNSPARSER_SoaRecord * soa
SOA data for SOA records.
struct GNUNET_DNSPARSER_SrvRecord * srv
SRV data for SRV records.
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
char * hostname
For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
union GNUNET_DNSPARSER_Record::@20 data
Payload of the record (which one of these is valid depends on the 'type').
struct GNUNET_DNSPARSER_UriRecord * uri
URI data for URI records.
uint32_t retry
Time interval that should elapse before a failed refresh should be retried.
char * mname
The domainname of the name server that was the original or primary source of data for this zone.
uint32_t refresh
Time interval before the zone should be refreshed.
uint32_t minimum_ttl
The bit minimum TTL field that should be exported with any RR from this zone.
char * rname
A domainname which specifies the mailbox of the person responsible for this zone.
uint32_t expire
Time value that specifies the upper limit on the time interval that can elapse before the zone is no ...
uint32_t serial
The version number of the original copy of the zone.
uint16_t port
TCP or UDP port of the service.
uint16_t weight
Relative weight for records with the same priority.
uint16_t priority
Preference for this entry (lower value is higher preference).
char * target
Hostname offering the service.
uint16_t priority
Preference for this entry (lower value is higher preference).
uint16_t weight
Relative weight for records with the same priority.
char * target
URI of the target, where the URI is as specified in RFC 3986.
Handle to the stub resolver.
Definition: dnsstub.c:125
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:46
Entry in list of pending tasks.
Definition: scheduler.c:136
uint16_t id
Unique identifier for the request/response.
Request we should make.
void * raw
Raw DNS query.
char * hostname
Hostname we are resolving, allocated at the end of this struct (optimizing memory consumption by redu...
struct Request * next
Active requests are kept in a DLL.
time_t time
When did we last issue this request?
struct GNUNET_CONTAINER_HeapNode * hn
Requests are kept in a heap while waiting to be resolved.
struct GNUNET_DNSSTUB_RequestSocket * rs
Socket used to make the request, NULL if not active.
int issue_num
How often did we issue this query?
size_t raw_len
Number of bytes in raw.
uint16_t id
random 16-bit DNS query identifier.
struct Request * prev
Active requests are kept in a DLL.
unsigned int issue_num
How often did we issue this query? (And failed, reset to zero once we were successful....