GNUnet  0.11.x
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 #include <gnunet_dnsstub_lib.h>
29 #include <gnunet_dnsparser_lib.h>
30 
34 struct Request
35 {
39  struct Request *next;
40 
44  struct Request *prev;
45 
50 
54  void *raw;
55 
59  size_t raw_len;
60 
64  char *hostname;
65 
69  time_t time;
70 
74  int issue_num;
75 
79  uint16_t id;
80 };
81 
82 
86 static struct GNUNET_DNSSTUB_Context *ctx;
87 
91 static unsigned int pending;
92 
96 static unsigned int lookups;
97 
101 static unsigned int failures;
102 
106 static unsigned int records;
107 
111 static struct Request *req_head;
112 
116 static struct Request *req_tail;
117 
121 static struct GNUNET_SCHEDULER_Task *t;
122 
126 #define THRESH 20
127 
132 #define TIME_THRESH 10
133 
137 #define MAX_RETRIES 5
138 
139 
146 static void
147 process_record (struct Request *req,
148  struct GNUNET_DNSPARSER_Record *rec)
149 {
150  char buf[INET6_ADDRSTRLEN];
151 
152  records++;
153  switch (rec->type)
154  {
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 
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 
176  fprintf (stdout,
177  "%s NS %s\n",
178  req->hostname,
179  rec->data.hostname);
180  break;
181 
183  fprintf (stdout,
184  "%s CNAME %s\n",
185  req->hostname,
186  rec->data.hostname);
187  break;
188 
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 
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 
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 
221  fprintf (stdout,
222  "%s PTR %s\n",
223  req->hostname,
224  rec->data.hostname);
225  break;
226 
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 
236  fprintf (stdout,
237  "%s DNAME %s\n",
238  req->hostname,
239  rec->data.hostname);
240  break;
241 
242  /* obscure records */
254 
255  /* DNSSEC */
264 
265  /* DNSSEC payload */
271 
272  /* obsolete records */
276  {
277  char *base32;
278 
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 
306 static void
307 process_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--;
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  }
333  req_tail,
334  req);
335  req->rs = NULL;
336  return;
337  }
338  if (req->id != dns->id)
339  return;
340  pending--;
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  {
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  }
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  {
376 
377  process_record (req,
378  rs);
379  }
380  for (unsigned int i = 0; i < p->num_additional_records; i++)
381  {
383 
384  process_record (req,
385  rs);
386  }
388  GNUNET_free (req->hostname);
389  GNUNET_free (req->raw);
390  GNUNET_free (req);
391 }
392 
393 
403 static int
404 submit_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,
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 
438 static void
439 process_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)
452  &process_queue,
453  NULL);
454  else
456 }
457 
458 
464 static void
465 do_shutdown (void *cls)
466 {
467  (void) cls;
468  if (NULL != t)
469  {
471  t = NULL;
472  }
473  GNUNET_DNSSTUB_stop (ctx);
474  ctx = NULL;
475 }
476 
477 
484 static void
485 run (void *cls)
486 {
487  (void) cls;
488 
490  NULL);
492  NULL);
493 }
494 
495 
501 static void
502 queue (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  {
515  "Refusing invalid hostname `%s'\n",
516  hostname);
517  return;
518  }
519  q.name = (char *) hostname;
522 
523  memset (&p,
524  0,
525  sizeof(p));
526  p.num_queries = 1;
527  p.queries = &q;
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);
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;
550  req_tail,
551  req);
552 }
553 
554 
562 int
563 main (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 !=
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  }
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 }
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void queue(const char *hostname)
Add hostname to the list of requests to be made.
struct GNUNET_DNSPARSER_Record * answers
Array of all answers in the packet, must contain "num_answers" entries.
static unsigned int lookups
Number of lookups we performed overall.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
#define GNUNET_DNSPARSER_TYPE_SIG
#define GNUNET_DNSPARSER_TYPE_AFSDB
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
uint32_t retry
Time interval that should elapse before a failed refresh should be retried.
uint32_t refresh
Time interval before the zone should be refreshed.
int main(int argc, char **argv)
Call with IP address of resolver to query.
static void do_shutdown(void *cls)
Clean up and terminate the process.
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.
char * mname
The domainname of the name server that was the original or primary source of data for this zone...
char * hostname
Hostname we are resolving.
#define GNUNET_DNSPARSER_TYPE_KX
#define GNUNET_DNSPARSER_TYPE_TKEY
#define GNUNET_DNSPARSER_TYPE_CNAME
char * mxhost
Name of the mail server.
struct GNUNET_DNSPARSER_SrvRecord * srv
SRV data for SRV records.
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1300
#define GNUNET_DNSPARSER_TYPE_SSHFP
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition: dnsstub.c:690
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:1257
#define GNUNET_DNSPARSER_TYPE_APL
uint16_t id
random 16-bit DNS query identifier.
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:591
uint16_t id
DNS ID (to match replies to requests).
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:717
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:854
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static struct GNUNET_SCHEDULER_Task * t
Main task.
struct GNUNET_DNSPARSER_Record * additional_records
Array of all additional answers in the packet, must contain "num_additional_records" entries...
#define GNUNET_DNSPARSER_TYPE_LOC
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:526
#define GNUNET_DNSPARSER_TYPE_NSEC3PARAM
#define GNUNET_DNSPARSER_TYPE_MX
unsigned int num_answers
Number of answers in the packet, should be 0 for queries.
uint16_t id
Unique identifier for the request/response.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
#define GNUNET_DNSPARSER_TYPE_HIP
uint32_t serial
The version number of the original copy of the zone.
static void process_queue(void *cls)
Process as many requests as possible from the queue.
#define GNUNET_DNSPARSER_TYPE_PTR
static unsigned int records
Number of records we found.
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
uint32_t minimum_ttl
The bit minimum TTL field that should be exported with any RR from this zone.
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:1253
#define GNUNET_DNSPARSER_TYPE_SOA
char * hostname
For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
struct GNUNET_DNSPARSER_SoaRecord * soa
SOA data for SOA records.
unsigned int num_additional_records
Number of additional records in the packet, should be 0 for queries.
#define GNUNET_DNSPARSER_TYPE_RP
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.
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
#define TIME_THRESH
TIME_THRESH is in usecs.
uint16_t port
TCP or UDP port of the service.
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:564
#define GNUNET_DNSPARSER_TYPE_TA
#define GNUNET_DNSPARSER_TYPE_DNAME
static void run(void *cls)
Process requests from the queue, then if the queue is not empty, try again.
char * target
Hostname offering the service.
#define THRESH
Maximum number of queries pending at the same time.
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:1280
#define MAX_RETRIES
How often do we retry a query before giving up for good?
struct GNUNET_CONTAINER_HeapNode * hn
Requests are kept in a heap while waiting to be resolved.
#define GNUNET_DNSPARSER_TYPE_DS
char * rname
A domainname which specifies the mailbox of the person responsible for this zone. ...
Randomness for IVs etc.
static char buf[2048]
union GNUNET_DNSPARSER_Record::@24 data
Payload of the record (which one of these is valid depends on the &#39;type&#39;).
A DNS response record.
struct GNUNET_DNSPARSER_Record * authority_records
Array of all authority records in the packet, must contain "num_authority_records" entries...
Handle to the stub resolver.
Definition: dnsstub.c:123
uint32_t expire
Time value that specifies the upper limit on the time interval that can elapse before the zone is no ...
struct GNUNET_DNSPARSER_Query * queries
Array of all queries in the packet, must contain "num_queries" entries.
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
#define GNUNET_DNSPARSER_TYPE_RRSIG
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
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:504
struct Request * prev
Requests are kept in a DLL.
#define GNUNET_DNSPARSER_TYPE_CDNSKEY
#define GNUNET_DNSPARSER_TYPE_IPSECKEY
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
size_t data_len
Number of bytes in data.
void * data
Binary record data.
int issue_num
How often did we issue this query?
#define GNUNET_DNSPARSER_TYPE_TXT
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_NAPTR
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
unsigned int num_authority_records
Number of authoritative answers in the packet, should be 0 for queries.
static unsigned int pending
The number of queries that are outstanding.
#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&#39;r...
#define GNUNET_DNSPARSER_TYPE_OPENPGPKEY
#define GNUNET_DNSPARSER_TYPE_URI
#define GNUNET_DNSPARSER_TYPE_TLSA
Request we should make.
struct GNUNET_DNSSTUB_RequestSocket * rs
Socket used to make the request, NULL if not active.
void * raw
Raw DNS query.
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
#define GNUNET_DNSPARSER_TYPE_KEY
#define GNUNET_DNSPARSER_TYPE_AAAA
void GNUNET_DNSSTUB_resolve_cancel(struct GNUNET_DNSSTUB_RequestSocket *rs)
Cancel DNS resolution.
Definition: dnsstub.c:540
#define GNUNET_DNSPARSER_TYPE_NS
#define GNUNET_DNSPARSER_TYPE_NSEC
Easy-to-process, parsed version of a DNS packet.
static unsigned int failures
Number of lookups that failed.
#define GNUNET_DNSPARSER_TYPE_CDS
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
struct Request * next
Requests are kept in a DLL.
#define GNUNET_DNSPARSER_TYPE_NSEC3
uint16_t priority
Preference for this entry (lower value is higher preference).
static struct Request * req_tail
Tail of DLL of all requests to perform.
char * name
Name of the record that the query is for (0-terminated).
unsigned int num_queries
Number of queries in the packet.
uint16_t weight
Relative weight for records with the same priority.
#define GNUNET_DNSPARSER_TYPE_DHCID
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:920
size_t raw_len
Number of bytes in raw.
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:44
#define GNUNET_DNSPARSER_TYPE_SRV
static void process_record(struct Request *req, struct GNUNET_DNSPARSER_Record *rec)
We received rec for req.
uint16_t preference
Preference for this entry (lower value is higher preference).
#define GNUNET_DNSPARSER_TYPE_TSIG
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
#define GNUNET_DNSPARSER_TYPE_A
static struct Request * req_head
Head of DLL of all requests to perform.
#define GNUNET_DNSPARSER_TYPE_CERT
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_DNSPARSER_TYPE_DNSKEY
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
time_t time
When did we last issue this request?