GNUnet  0.20.0
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 
32 struct 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 
72  int issue_num;
73 
77  uint16_t id;
78 };
79 
80 
84 static struct GNUNET_DNSSTUB_Context *ctx;
85 
89 static unsigned int pending;
90 
94 static unsigned int lookups;
95 
99 static unsigned int failures;
100 
104 static unsigned int records;
105 
109 static struct Request *req_head;
110 
114 static struct Request *req_tail;
115 
119 static struct GNUNET_SCHEDULER_Task *t;
120 
124 #define THRESH 20
125 
130 #define TIME_THRESH 10
131 
135 #define MAX_RETRIES 5
136 
137 
144 static void
145 process_record (struct Request *req,
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 PTR %s\n",
221  req->hostname,
222  rec->data.hostname);
223  break;
224 
226  fprintf (stdout,
227  "%s TXT %.*s\n",
228  req->hostname,
229  (int) rec->data.raw.data_len,
230  (char *) rec->data.raw.data);
231  break;
232 
234  fprintf (stdout,
235  "%s DNAME %s\n",
236  req->hostname,
237  rec->data.hostname);
238  break;
239 
240  /* obscure records */
252 
253  /* DNSSEC */
262 
263  /* DNSSEC payload */
269 
270  /* obsolete records */
274  {
275  char *base32;
276 
278  rec->data.raw.data_len);
279  fprintf (stdout,
280  "%s (%u) %s\n",
281  req->hostname,
282  rec->type,
283  base32);
284  GNUNET_free (base32);
285  }
286  break;
287 
288  default:
289  fprintf (stderr,
290  "Unsupported type %u\n",
291  (unsigned int) rec->type);
292  break;
293  }
294 }
295 
296 
304 static void
305 process_result (void *cls,
306  const struct GNUNET_TUN_DnsHeader *dns,
307  size_t dns_len)
308 {
309  struct Request *req = cls;
310  struct GNUNET_DNSPARSER_Packet *p;
311 
312  if (NULL == dns)
313  {
314  /* stub gave up */
315  pending--;
317  "Stub gave up on DNS reply for `%s'\n",
318  req->hostname);
320  req_tail,
321  req);
322  if (req->issue_num > MAX_RETRIES)
323  {
324  failures++;
325  GNUNET_free (req->hostname);
326  GNUNET_free (req->raw);
327  GNUNET_free (req);
328  return;
329  }
331  req_tail,
332  req);
333  req->rs = NULL;
334  return;
335  }
336  if (req->id != dns->id)
337  return;
338  pending--;
340  req->rs = NULL;
342  req_tail,
343  req);
344  p = GNUNET_DNSPARSER_parse ((const char *) dns,
345  dns_len);
346  if (NULL == p)
347  {
349  "Failed to parse DNS reply for `%s'\n",
350  req->hostname);
351  if (req->issue_num > MAX_RETRIES)
352  {
353  failures++;
354  GNUNET_free (req->hostname);
355  GNUNET_free (req->raw);
356  GNUNET_free (req);
357  return;
358  }
360  req_tail,
361  req);
362  return;
363  }
364  for (unsigned int i = 0; i < p->num_answers; i++)
365  {
366  struct GNUNET_DNSPARSER_Record *rs = &p->answers[i];
367 
368  process_record (req,
369  rs);
370  }
371  for (unsigned int i = 0; i < p->num_authority_records; i++)
372  {
373  struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i];
374 
375  process_record (req,
376  rs);
377  }
378  for (unsigned int i = 0; i < p->num_additional_records; i++)
379  {
380  struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i];
381 
382  process_record (req,
383  rs);
384  }
386  GNUNET_free (req->hostname);
387  GNUNET_free (req->raw);
388  GNUNET_free (req);
389 }
390 
391 
401 static int
402 submit_req (struct Request *req)
403 {
404  static struct timeval last_request;
405  struct timeval now;
406 
407  if (NULL != req->rs)
408  return GNUNET_NO; /* already submitted */
409  gettimeofday (&now,
410  NULL);
411  if ((((now.tv_sec - last_request.tv_sec) == 0) &&
412  ((now.tv_usec - last_request.tv_usec) < TIME_THRESH)) ||
413  (pending >= THRESH))
414  return GNUNET_SYSERR;
415  GNUNET_assert (NULL == req->rs);
416  req->rs = GNUNET_DNSSTUB_resolve (ctx,
417  req->raw,
418  req->raw_len,
420  req);
421  GNUNET_assert (NULL != req->rs);
422  req->issue_num++;
423  last_request = now;
424  lookups++;
425  pending++;
426  req->time = time (NULL);
427  return GNUNET_OK;
428 }
429 
430 
436 static void
437 process_queue (void *cls)
438 {
439  (void) cls;
440  t = NULL;
441  for (struct Request *req = req_head;
442  NULL != req;
443  req = req->next)
444  {
445  if (GNUNET_SYSERR == submit_req (req))
446  break;
447  }
448  if (NULL != req_head)
450  &process_queue,
451  NULL);
452  else
454 }
455 
456 
462 static void
463 do_shutdown (void *cls)
464 {
465  (void) cls;
466  if (NULL != t)
467  {
469  t = NULL;
470  }
472  ctx = NULL;
473 }
474 
475 
482 static void
483 run (void *cls)
484 {
485  (void) cls;
486 
488  NULL);
490  NULL);
491 }
492 
493 
499 static void
500 queue (const char *hostname)
501 {
502  struct GNUNET_DNSPARSER_Packet p;
503  struct GNUNET_DNSPARSER_Query q;
504  struct Request *req;
505  char *raw;
506  size_t raw_size;
507  int ret;
508 
509  if (GNUNET_OK !=
511  {
513  "Refusing invalid hostname `%s'\n",
514  hostname);
515  return;
516  }
517  q.name = (char *) hostname;
519  q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
520 
521  memset (&p,
522  0,
523  sizeof(p));
524  p.num_queries = 1;
525  p.queries = &q;
527  UINT16_MAX);
529  UINT16_MAX,
530  &raw,
531  &raw_size);
532  if (GNUNET_OK != ret)
533  {
534  if (GNUNET_NO == ret)
535  GNUNET_free (raw);
537  "Failed to pack query for hostname `%s'\n",
538  hostname);
539  return;
540  }
541 
542  req = GNUNET_new (struct Request);
543  req->hostname = strdup (hostname);
544  req->raw = raw;
545  req->raw_len = raw_size;
546  req->id = p.id;
548  req_tail,
549  req);
550 }
551 
552 
560 int
561 main (int argc,
562  char **argv)
563 {
564  char hn[256];
565 
566  if (2 != argc)
567  {
568  fprintf (stderr,
569  "Missing required configuration argument\n");
570  return -1;
571  }
572  ctx = GNUNET_DNSSTUB_start (256);
573  if (NULL == ctx)
574  {
575  fprintf (stderr,
576  "Failed to initialize GNUnet DNS STUB\n");
577  return 1;
578  }
579  if (GNUNET_OK !=
581  argv[1]))
582  {
583  fprintf (stderr,
584  "Failed to use `%s' for DNS resolver\n",
585  argv[1]);
586  return 1;
587  }
588 
589  while (NULL !=
590  fgets (hn,
591  sizeof(hn),
592  stdin))
593  {
594  if (strlen (hn) > 0)
595  hn[strlen (hn) - 1] = '\0'; /* eat newline */
596  queue (hn);
597  }
599  NULL);
600  fprintf (stderr,
601  "Did %u lookups, found %u records, %u lookups failed, %u pending on shutdown\n",
602  lookups,
603  records,
604  failures,
605  pending);
606  return 0;
607 }
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static int raw
raw output
Definition: gnunet-gns.c:78
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
static char * hostname
Our hostname; we give this to all the peers we start.
static char buf[2048]
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:854
#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_NSEC
#define GNUNET_DNSPARSER_TYPE_DS
#define GNUNET_DNSPARSER_TYPE_PTR
#define GNUNET_DNSPARSER_TYPE_HIP
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:656
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:1259
#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
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_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:586
void GNUNET_DNSSTUB_resolve_cancel(struct GNUNET_DNSSTUB_RequestSocket *rs)
Cancel DNS resolution.
Definition: dnsstub.c:562
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
#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:562
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:720
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:1299
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:1334
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
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:1272
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:763
#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_*.
union GNUNET_DNSPARSER_Record::@24 data
Payload of the record (which one of these is valid depends on the 'type').
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
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.
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.
struct Request * next
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
Requests are kept in a DLL.