GNUnet  0.10.x
dnsparser.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2010-2014, 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 
27 #include "platform.h"
28 #if HAVE_LIBIDN2
29 #if HAVE_IDN2_H
30 #include <idn2.h>
31 #elif HAVE_IDN2_IDN2_H
32 #include <idn2/idn2.h>
33 #endif
34 #elif HAVE_LIBIDN
35 #if HAVE_IDNA_H
36 #include <idna.h>
37 #elif HAVE_IDN_IDNA_H
38 #include <idn/idna.h>
39 #endif
40 #endif
41 #if WINDOWS
42 #include <idn-free.h>
43 #endif
44 #include "gnunet_util_lib.h"
45 
46 
55 int
56 GNUNET_DNSPARSER_check_label (const char *label)
57 {
58  char *output;
59  size_t slen;
60 
61  if (NULL != strchr (label, '.'))
62  return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */
63  if (0 == strcmp (label, "@")) /* '@' is reserved for the empty label, see #GNUNET_GNS_EMPTY_LABEL_AT */
64  return GNUNET_SYSERR;
65  if (IDNA_SUCCESS != idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED))
66  return GNUNET_SYSERR;
67  slen = strlen (output);
68 #if WINDOWS
69  idn_free (output);
70 #else
71  free (output);
72 #endif
73  return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK;
74 }
75 
76 
85 int
87 {
88  char *ldup;
89  char *output;
90  size_t slen;
91  char *tok;
92 
93  ldup = GNUNET_strdup (name);
94  for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, "."))
96  {
97  GNUNET_free (ldup);
98  return GNUNET_SYSERR;
99  }
100  GNUNET_free (ldup);
101  if (IDNA_SUCCESS != idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED))
102  return GNUNET_SYSERR;
103  slen = strlen (output);
104 #if WINDOWS
105  idn_free (output);
106 #else
107  free (output);
108 #endif
109  return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK;
110 }
111 
112 
118 void
120 {
121  if (NULL == soa)
122  return;
125  GNUNET_free (soa);
126 }
127 
128 
134 void
136 {
137  if (NULL == cert)
138  return;
140  GNUNET_free (cert);
141 }
142 
143 
149 void
151 {
152  if (NULL == srv)
153  return;
155  GNUNET_free (srv);
156 }
157 
158 
164 void
166 {
167  if (NULL == mx)
168  return;
170  GNUNET_free (mx);
171 }
172 
173 
179 void
181 {
183  switch (r->type)
184  {
187  break;
190  break;
193  break;
196  break;
201  break;
202  default:
204  break;
205  }
206 }
207 
208 
219 static char *
220 parse_name (const char *udp_payload,
221  size_t udp_payload_length,
222  size_t *off,
223  unsigned int depth)
224 {
225  const uint8_t *input = (const uint8_t *) udp_payload;
226  char *ret;
227  char *tmp;
228  char *xstr;
229  uint8_t len;
230  size_t xoff;
231  char *utf8;
232  Idna_rc rc;
233 
234  ret = GNUNET_strdup ("");
235  while (1)
236  {
237  if (*off >= udp_payload_length)
238  {
239  GNUNET_break_op (0);
240  goto error;
241  }
242  len = input[*off];
243  if (0 == len)
244  {
245  (*off)++;
246  break;
247  }
248  if (len < 64)
249  {
250  if (*off + 1 + len > udp_payload_length)
251  {
252  GNUNET_break_op (0);
253  goto error;
254  }
255  GNUNET_asprintf (&tmp, "%.*s", (int) len, &udp_payload[*off + 1]);
256  if (IDNA_SUCCESS !=
257  (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED)))
258  {
260  _ ("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
261  tmp,
262  idna_strerror (rc));
263  GNUNET_free (tmp);
264  GNUNET_asprintf (&tmp,
265  "%s%.*s.",
266  ret,
267  (int) len,
268  &udp_payload[*off + 1]);
269  }
270  else
271  {
272  GNUNET_free (tmp);
273  GNUNET_asprintf (&tmp, "%s%s.", ret, utf8);
274 #if WINDOWS
275  idn_free (utf8);
276 #else
277  free (utf8);
278 #endif
279  }
280  GNUNET_free (ret);
281  ret = tmp;
282  *off += 1 + len;
283  }
284  else if ((64 | 128) == (len & (64 | 128)))
285  {
286  if (depth > 32)
287  {
288  GNUNET_break_op (0);
289  goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */
290  }
291  /* pointer to string */
292  if (*off + 1 > udp_payload_length)
293  {
294  GNUNET_break_op (0);
295  goto error;
296  }
297  xoff = ((len - (64 | 128)) << 8) + input[*off + 1];
298  xstr = parse_name (udp_payload, udp_payload_length, &xoff, depth + 1);
299  if (NULL == xstr)
300  {
301  GNUNET_break_op (0);
302  goto error;
303  }
304  GNUNET_asprintf (&tmp, "%s%s.", ret, xstr);
305  GNUNET_free (ret);
306  GNUNET_free (xstr);
307  ret = tmp;
308  if (strlen (ret) > udp_payload_length)
309  {
310  GNUNET_break_op (0);
311  goto error; /* we are looping (building an infinite string) */
312  }
313  *off += 2;
314  /* pointers always terminate names */
315  break;
316  }
317  else
318  {
319  /* neither pointer nor inline string, not supported... */
320  GNUNET_break_op (0);
321  goto error;
322  }
323  }
324  if (0 < strlen (ret))
325  ret[strlen (ret) - 1] = '\0'; /* eat tailing '.' */
326  return ret;
327 error:
328  GNUNET_break_op (0);
329  GNUNET_free (ret);
330  return NULL;
331 }
332 
333 
343 char *
344 GNUNET_DNSPARSER_parse_name (const char *udp_payload,
345  size_t udp_payload_length,
346  size_t *off)
347 {
348  return parse_name (udp_payload, udp_payload_length, off, 0);
349 }
350 
351 
362 int
363 GNUNET_DNSPARSER_parse_query (const char *udp_payload,
364  size_t udp_payload_length,
365  size_t *off,
366  struct GNUNET_DNSPARSER_Query *q)
367 {
368  char *name;
369  struct GNUNET_TUN_DnsQueryLine ql;
370 
371  name = GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
372  if (NULL == name)
373  {
374  GNUNET_break_op (0);
375  return GNUNET_SYSERR;
376  }
377  q->name = name;
378  if (*off + sizeof (struct GNUNET_TUN_DnsQueryLine) > udp_payload_length)
379  {
380  GNUNET_break_op (0);
381  return GNUNET_SYSERR;
382  }
383  GNUNET_memcpy (&ql, &udp_payload[*off], sizeof (ql));
384  *off += sizeof (ql);
385  q->type = ntohs (ql.type);
386  q->dns_traffic_class = ntohs (ql.dns_traffic_class);
387  return GNUNET_OK;
388 }
389 
390 
401 GNUNET_DNSPARSER_parse_soa (const char *udp_payload,
402  size_t udp_payload_length,
403  size_t *off)
404 {
405  struct GNUNET_DNSPARSER_SoaRecord *soa;
406  struct GNUNET_TUN_DnsSoaRecord soa_bin;
407  size_t old_off;
408 
409  old_off = *off;
410  soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord);
411  soa->mname =
412  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
413  soa->rname =
414  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
415  if ((NULL == soa->mname) || (NULL == soa->rname) ||
416  (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length))
417  {
418  GNUNET_break_op (0);
420  *off = old_off;
421  return NULL;
422  }
423  GNUNET_memcpy (&soa_bin,
424  &udp_payload[*off],
425  sizeof (struct GNUNET_TUN_DnsSoaRecord));
426  soa->serial = ntohl (soa_bin.serial);
427  soa->refresh = ntohl (soa_bin.refresh);
428  soa->retry = ntohl (soa_bin.retry);
429  soa->expire = ntohl (soa_bin.expire);
430  soa->minimum_ttl = ntohl (soa_bin.minimum);
431  (*off) += sizeof (struct GNUNET_TUN_DnsSoaRecord);
432  return soa;
433 }
434 
435 
446 GNUNET_DNSPARSER_parse_mx (const char *udp_payload,
447  size_t udp_payload_length,
448  size_t *off)
449 {
450  struct GNUNET_DNSPARSER_MxRecord *mx;
451  uint16_t mxpref;
452  size_t old_off;
453 
454  old_off = *off;
455  if (*off + sizeof (uint16_t) > udp_payload_length)
456  {
457  GNUNET_break_op (0);
458  return NULL;
459  }
460  GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t));
461  (*off) += sizeof (uint16_t);
463  mx->preference = ntohs (mxpref);
464  mx->mxhost =
465  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
466  if (NULL == mx->mxhost)
467  {
468  GNUNET_break_op (0);
470  *off = old_off;
471  return NULL;
472  }
473  return mx;
474 }
475 
476 
487 GNUNET_DNSPARSER_parse_srv (const char *udp_payload,
488  size_t udp_payload_length,
489  size_t *off)
490 {
491  struct GNUNET_DNSPARSER_SrvRecord *srv;
492  struct GNUNET_TUN_DnsSrvRecord srv_bin;
493  size_t old_off;
494 
495  old_off = *off;
496  if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length)
497  return NULL;
498  GNUNET_memcpy (&srv_bin,
499  &udp_payload[*off],
500  sizeof (struct GNUNET_TUN_DnsSrvRecord));
501  (*off) += sizeof (struct GNUNET_TUN_DnsSrvRecord);
502  srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord);
503  srv->priority = ntohs (srv_bin.prio);
504  srv->weight = ntohs (srv_bin.weight);
505  srv->port = ntohs (srv_bin.port);
506  srv->target =
507  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
508  if (NULL == srv->target)
509  {
511  *off = old_off;
512  return NULL;
513  }
514  return srv;
515 }
516 
517 
528 GNUNET_DNSPARSER_parse_cert (const char *udp_payload,
529  size_t udp_payload_length,
530  size_t *off)
531 {
532  struct GNUNET_DNSPARSER_CertRecord *cert;
533  struct GNUNET_TUN_DnsCertRecord dcert;
534 
535  if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) >= udp_payload_length)
536  {
537  GNUNET_break_op (0);
538  return NULL;
539  }
540  GNUNET_memcpy (&dcert,
541  &udp_payload[*off],
542  sizeof (struct GNUNET_TUN_DnsCertRecord));
543  (*off) += sizeof (struct GNUNET_TUN_DnsCertRecord);
544  cert = GNUNET_new (struct GNUNET_DNSPARSER_CertRecord);
545  cert->cert_type = ntohs (dcert.cert_type);
546  cert->cert_tag = ntohs (dcert.cert_tag);
547  cert->algorithm = dcert.algorithm;
548  cert->certificate_size = udp_payload_length - (*off);
551  &udp_payload[*off],
552  cert->certificate_size);
553  (*off) += cert->certificate_size;
554  return cert;
555 }
556 
557 
568 int
569 GNUNET_DNSPARSER_parse_record (const char *udp_payload,
570  size_t udp_payload_length,
571  size_t *off,
572  struct GNUNET_DNSPARSER_Record *r)
573 {
574  char *name;
575  struct GNUNET_TUN_DnsRecordLine rl;
576  size_t old_off;
577  uint16_t data_len;
578 
579  name = GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
580  if (NULL == name)
581  {
582  GNUNET_break_op (0);
583  return GNUNET_SYSERR;
584  }
585  r->name = name;
586  if (*off + sizeof (struct GNUNET_TUN_DnsRecordLine) > udp_payload_length)
587  {
588  GNUNET_break_op (0);
589  return GNUNET_SYSERR;
590  }
591  GNUNET_memcpy (&rl, &udp_payload[*off], sizeof (rl));
592  (*off) += sizeof (rl);
593  r->type = ntohs (rl.type);
594  r->dns_traffic_class = ntohs (rl.dns_traffic_class);
597  data_len = ntohs (rl.data_len);
598  if (*off + data_len > udp_payload_length)
599  {
600  GNUNET_break_op (0);
601  return GNUNET_SYSERR;
602  }
603  old_off = *off;
604  switch (r->type)
605  {
610  r->data.hostname =
611  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
612  if ((NULL == r->data.hostname) || (old_off + data_len != *off))
613  return GNUNET_SYSERR;
614  return GNUNET_OK;
616  r->data.soa =
617  GNUNET_DNSPARSER_parse_soa (udp_payload, udp_payload_length, off);
618  if ((NULL == r->data.soa) || (old_off + data_len != *off))
619  {
620  GNUNET_break_op (0);
621  return GNUNET_SYSERR;
622  }
623  return GNUNET_OK;
625  r->data.mx =
626  GNUNET_DNSPARSER_parse_mx (udp_payload, udp_payload_length, off);
627  if ((NULL == r->data.mx) || (old_off + data_len != *off))
628  {
629  GNUNET_break_op (0);
630  return GNUNET_SYSERR;
631  }
632  return GNUNET_OK;
634  r->data.srv =
635  GNUNET_DNSPARSER_parse_srv (udp_payload, udp_payload_length, off);
636  if ((NULL == r->data.srv) || (old_off + data_len != *off))
637  {
638  GNUNET_break_op (0);
639  return GNUNET_SYSERR;
640  }
641  return GNUNET_OK;
642  default:
643  r->data.raw.data = GNUNET_malloc (data_len);
644  r->data.raw.data_len = data_len;
645  GNUNET_memcpy (r->data.raw.data, &udp_payload[*off], data_len);
646  break;
647  }
648  (*off) += data_len;
649  return GNUNET_OK;
650 }
651 
652 
662 GNUNET_DNSPARSER_parse (const char *udp_payload, size_t udp_payload_length)
663 {
664  struct GNUNET_DNSPARSER_Packet *p;
665  const struct GNUNET_TUN_DnsHeader *dns;
666  size_t off;
667  unsigned int n;
668 
669  if (udp_payload_length < sizeof (struct GNUNET_TUN_DnsHeader))
670  return NULL;
671  dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload;
672  off = sizeof (struct GNUNET_TUN_DnsHeader);
673  p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
674  p->flags = dns->flags;
675  p->id = dns->id;
676  n = ntohs (dns->query_count);
677  if (n > 0)
678  {
680  p->num_queries = n;
681  for (unsigned int i = 0; i < n; i++)
682  if (GNUNET_OK != GNUNET_DNSPARSER_parse_query (udp_payload,
683  udp_payload_length,
684  &off,
685  &p->queries[i]))
686  goto error;
687  }
688  n = ntohs (dns->answer_rcount);
689  if (n > 0)
690  {
692  p->num_answers = n;
693  for (unsigned int i = 0; i < n; i++)
694  if (GNUNET_OK != GNUNET_DNSPARSER_parse_record (udp_payload,
695  udp_payload_length,
696  &off,
697  &p->answers[i]))
698  goto error;
699  }
700  n = ntohs (dns->authority_rcount);
701  if (n > 0)
702  {
704  p->num_authority_records = n;
705  for (unsigned int i = 0; i < n; i++)
706  if (GNUNET_OK != GNUNET_DNSPARSER_parse_record (udp_payload,
707  udp_payload_length,
708  &off,
709  &p->authority_records[i]))
710  goto error;
711  }
712  n = ntohs (dns->additional_rcount);
713  if (n > 0)
714  {
715  p->additional_records =
717  p->num_additional_records = n;
718  for (unsigned int i = 0; i < n; i++)
719  {
720  if (GNUNET_OK !=
721  GNUNET_DNSPARSER_parse_record (udp_payload,
722  udp_payload_length,
723  &off,
724  &p->additional_records[i]))
725  goto error;
726  }
727  }
728  return p;
729 error:
730  GNUNET_break_op (0);
732  return NULL;
733 }
734 
735 
744 {
745  struct GNUNET_DNSPARSER_Record *dup = GNUNET_memdup (r, sizeof (*r));
746 
747  dup->name = GNUNET_strdup (r->name);
748  switch (r->type)
749  {
754  break;
755  }
758  break;
759  }
762  break;
763  }
766  break;
767  }
770  break;
771  }
772  default: {
774  }
775  }
776  return dup;
777 }
778 
779 
788  const struct GNUNET_DNSPARSER_SoaRecord *r)
789 {
790  struct GNUNET_DNSPARSER_SoaRecord *dup = GNUNET_memdup (r, sizeof (*r));
791 
792  dup->mname = GNUNET_strdup (r->mname);
793  dup->rname = GNUNET_strdup (r->rname);
794  return dup;
795 }
796 
797 
806  const struct GNUNET_DNSPARSER_CertRecord *r)
807 {
808  struct GNUNET_DNSPARSER_CertRecord *dup = GNUNET_memdup (r, sizeof (*r));
809 
811  return dup;
812 }
813 
814 
823 {
824  struct GNUNET_DNSPARSER_MxRecord *dup = GNUNET_memdup (r, sizeof (*r));
825 
826  dup->mxhost = GNUNET_strdup (r->mxhost);
827  return dup;
828 }
829 
830 
839  const struct GNUNET_DNSPARSER_SrvRecord *r)
840 {
841  struct GNUNET_DNSPARSER_SrvRecord *dup = GNUNET_memdup (r, sizeof (*r));
842 
843  dup->target = GNUNET_strdup (r->target);
844  return dup;
845 }
846 
847 
853 void
855 {
856  for (unsigned int i = 0; i < p->num_queries; i++)
859  for (unsigned int i = 0; i < p->num_answers; i++)
862  for (unsigned int i = 0; i < p->num_authority_records; i++)
865  for (unsigned int i = 0; i < p->num_additional_records; i++)
868  GNUNET_free (p);
869 }
870 
871 
872 /* ********************** DNS packet assembly code **************** */
873 
874 
888 int
890  size_t dst_len,
891  size_t *off,
892  const char *name)
893 {
894  const char *dot;
895  const char *idna_name;
896  char *idna_start;
897  size_t start;
898  size_t pos;
899  size_t len;
900  Idna_rc rc;
901 
902  if (NULL == name)
903  return GNUNET_SYSERR;
904 
905  if (IDNA_SUCCESS !=
906  (rc = idna_to_ascii_8z (name, &idna_start, IDNA_ALLOW_UNASSIGNED)))
907  {
909  _ (
910  "Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"),
911  name,
912  idna_strerror (rc));
913  return GNUNET_NO;
914  }
915  idna_name = idna_start;
916  start = *off;
917  if (start + strlen (idna_name) + 2 > dst_len)
918  goto fail;
919  pos = start;
920  do
921  {
922  dot = strchr (idna_name, '.');
923  if (NULL == dot)
924  len = strlen (idna_name);
925  else
926  len = dot - idna_name;
927  if ((len >= 64) || (0 == len))
928  {
930  "Invalid DNS name `%s': label with %u characters encountered\n",
931  name,
932  (unsigned int) len);
933  goto fail; /* label too long or empty */
934  }
935  dst[pos++] = (char) (uint8_t) len;
936  GNUNET_memcpy (&dst[pos], idna_name, len);
937  pos += len;
938  idna_name += len + 1; /* also skip dot */
939  } while (NULL != dot);
940  dst[pos++] = '\0'; /* terminator */
941  *off = pos;
942 #if WINDOWS
943  idn_free (idna_start);
944 #else
945  free (idna_start);
946 #endif
947  return GNUNET_OK;
948 fail:
949 #if WINDOWS
950  idn_free (idna_start);
951 #else
952  free (idna_start);
953 #endif
954  return GNUNET_NO;
955 }
956 
957 
970 int
972  size_t dst_len,
973  size_t *off,
974  const struct GNUNET_DNSPARSER_Query *query)
975 {
976  int ret;
977  struct GNUNET_TUN_DnsQueryLine ql;
978 
980  dst_len -
981  sizeof (
982  struct GNUNET_TUN_DnsQueryLine),
983  off,
984  query->name);
985  if (ret != GNUNET_OK)
986  return ret;
987  ql.type = htons (query->type);
988  ql.dns_traffic_class = htons (query->dns_traffic_class);
989  GNUNET_memcpy (&dst[*off], &ql, sizeof (ql));
990  (*off) += sizeof (ql);
991  return GNUNET_OK;
992 }
993 
994 
1007 int
1009  size_t dst_len,
1010  size_t *off,
1011  const struct GNUNET_DNSPARSER_MxRecord *mx)
1012 {
1013  uint16_t mxpref;
1014 
1015  if (*off + sizeof (uint16_t) > dst_len)
1016  return GNUNET_NO;
1017  mxpref = htons (mx->preference);
1018  GNUNET_memcpy (&dst[*off], &mxpref, sizeof (mxpref));
1019  (*off) += sizeof (mxpref);
1020  return GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, mx->mxhost);
1021 }
1022 
1023 
1036 int
1038  char *dst,
1039  size_t dst_len,
1040  size_t *off,
1041  const struct GNUNET_DNSPARSER_CertRecord *cert)
1042 {
1043  struct GNUNET_TUN_DnsCertRecord dcert;
1044 
1045 #ifdef __clang__
1046 #pragma clang diagnostic push
1047 #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
1048 #endif
1049  if ((cert->cert_type > UINT16_MAX) || (cert->algorithm > UINT8_MAX))
1050  {
1051  GNUNET_break (0);
1052  return GNUNET_SYSERR;
1053  }
1054 #ifdef __clang__
1055 #pragma clang diagnostic pop
1056 #endif
1057  if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size >
1058  dst_len)
1059  return GNUNET_NO;
1060  dcert.cert_type = htons ((uint16_t) cert->cert_type);
1061  dcert.cert_tag = htons ((uint16_t) cert->cert_tag);
1062  dcert.algorithm = (uint8_t) cert->algorithm;
1063  GNUNET_memcpy (&dst[*off], &dcert, sizeof (dcert));
1064  (*off) += sizeof (dcert);
1065  GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size);
1066  (*off) += cert->certificate_size;
1067  return GNUNET_OK;
1068 }
1069 
1070 
1083 int
1085  size_t dst_len,
1086  size_t *off,
1087  const struct GNUNET_DNSPARSER_SoaRecord *soa)
1088 {
1089  struct GNUNET_TUN_DnsSoaRecord sd;
1090  int ret;
1091 
1092  if ((GNUNET_OK !=
1093  (ret =
1094  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->mname))) ||
1095  (GNUNET_OK !=
1096  (ret =
1097  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->rname))))
1098  return ret;
1099  if (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > dst_len)
1100  return GNUNET_NO;
1101  sd.serial = htonl (soa->serial);
1102  sd.refresh = htonl (soa->refresh);
1103  sd.retry = htonl (soa->retry);
1104  sd.expire = htonl (soa->expire);
1105  sd.minimum = htonl (soa->minimum_ttl);
1106  GNUNET_memcpy (&dst[*off], &sd, sizeof (sd));
1107  (*off) += sizeof (sd);
1108  return GNUNET_OK;
1109 }
1110 
1111 
1124 int
1126  size_t dst_len,
1127  size_t *off,
1128  const struct GNUNET_DNSPARSER_SrvRecord *srv)
1129 {
1130  struct GNUNET_TUN_DnsSrvRecord sd;
1131  int ret;
1132 
1133  if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > dst_len)
1134  return GNUNET_NO;
1135  sd.prio = htons (srv->priority);
1136  sd.weight = htons (srv->weight);
1137  sd.port = htons (srv->port);
1138  GNUNET_memcpy (&dst[*off], &sd, sizeof (sd));
1139  (*off) += sizeof (sd);
1140  if (GNUNET_OK !=
1141  (ret =
1142  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, srv->target)))
1143  return ret;
1144  return GNUNET_OK;
1145 }
1146 
1147 
1160 static int
1161 add_record (char *dst,
1162  size_t dst_len,
1163  size_t *off,
1164  const struct GNUNET_DNSPARSER_Record *record)
1165 {
1166  int ret;
1167  size_t start;
1168  size_t pos;
1169  struct GNUNET_TUN_DnsRecordLine rl;
1170 
1171  start = *off;
1173  dst_len -
1174  sizeof (
1175  struct GNUNET_TUN_DnsRecordLine),
1176  off,
1177  record->name);
1178  if (GNUNET_OK != ret)
1179  return ret;
1180  /* '*off' is now the position where we will need to write the record line */
1181 
1182  pos = *off + sizeof (struct GNUNET_TUN_DnsRecordLine);
1183  switch (record->type)
1184  {
1186  ret = GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &pos, record->data.mx);
1187  break;
1189  ret =
1190  GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &pos, record->data.cert);
1191  break;
1193  ret =
1194  GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &pos, record->data.soa);
1195  break;
1200  dst_len,
1201  &pos,
1202  record->data.hostname);
1203  break;
1205  ret =
1206  GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &pos, record->data.srv);
1207  break;
1208  default:
1209  if (pos + record->data.raw.data_len > dst_len)
1210  {
1211  ret = GNUNET_NO;
1212  break;
1213  }
1214  GNUNET_memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
1215  pos += record->data.raw.data_len;
1216  ret = GNUNET_OK;
1217  break;
1218  }
1219  if (GNUNET_OK != ret)
1220  {
1221  *off = start;
1222  return GNUNET_NO;
1223  }
1224 
1225  if (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX)
1226  {
1227  /* record data too long */
1228  *off = start;
1229  return GNUNET_NO;
1230  }
1231  rl.type = htons (record->type);
1232  rl.dns_traffic_class = htons (record->dns_traffic_class);
1233  rl.ttl = htonl (
1235  1000LL / 1000LL); /* in seconds */
1236  rl.data_len = htons (
1237  (uint16_t) (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine))));
1238  GNUNET_memcpy (&dst[*off], &rl, sizeof (struct GNUNET_TUN_DnsRecordLine));
1239  *off = pos;
1240  return GNUNET_OK;
1241 }
1242 
1243 
1258 int
1260  uint16_t max,
1261  char **buf,
1262  size_t *buf_length)
1263 {
1264  struct GNUNET_TUN_DnsHeader dns;
1265  size_t off;
1266  char tmp[max];
1267  int ret;
1268  int trc;
1269 
1270  if ((p->num_queries > UINT16_MAX) || (p->num_answers > UINT16_MAX) ||
1271  (p->num_authority_records > UINT16_MAX) ||
1272  (p->num_additional_records > UINT16_MAX))
1273  return GNUNET_SYSERR;
1274  dns.id = p->id;
1275  dns.flags = p->flags;
1276  dns.query_count = htons (p->num_queries);
1277  dns.answer_rcount = htons (p->num_answers);
1278  dns.authority_rcount = htons (p->num_authority_records);
1279  dns.additional_rcount = htons (p->num_additional_records);
1280 
1281  off = sizeof (struct GNUNET_TUN_DnsHeader);
1282  trc = GNUNET_NO;
1283  for (unsigned int i = 0; i < p->num_queries; i++)
1284  {
1286  sizeof (tmp),
1287  &off,
1288  &p->queries[i]);
1289  if (GNUNET_SYSERR == ret)
1290  return GNUNET_SYSERR;
1291  if (GNUNET_NO == ret)
1292  {
1293  dns.query_count = htons ((uint16_t) (i - 1));
1294  trc = GNUNET_YES;
1295  break;
1296  }
1297  }
1298  for (unsigned int i = 0; i < p->num_answers; i++)
1299  {
1300  ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]);
1301  if (GNUNET_SYSERR == ret)
1302  return GNUNET_SYSERR;
1303  if (GNUNET_NO == ret)
1304  {
1305  dns.answer_rcount = htons ((uint16_t) (i - 1));
1306  trc = GNUNET_YES;
1307  break;
1308  }
1309  }
1310  for (unsigned int i = 0; i < p->num_authority_records; i++)
1311  {
1312  ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]);
1313  if (GNUNET_SYSERR == ret)
1314  return GNUNET_SYSERR;
1315  if (GNUNET_NO == ret)
1316  {
1317  dns.authority_rcount = htons ((uint16_t) (i - 1));
1318  trc = GNUNET_YES;
1319  break;
1320  }
1321  }
1322  for (unsigned int i = 0; i < p->num_additional_records; i++)
1323  {
1324  ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]);
1325  if (GNUNET_SYSERR == ret)
1326  return GNUNET_SYSERR;
1327  if (GNUNET_NO == ret)
1328  {
1329  dns.additional_rcount = htons (i - 1);
1330  trc = GNUNET_YES;
1331  break;
1332  }
1333  }
1334 
1335  if (GNUNET_YES == trc)
1336  dns.flags.message_truncated = 1;
1337  GNUNET_memcpy (tmp, &dns, sizeof (struct GNUNET_TUN_DnsHeader));
1338 
1339  *buf = GNUNET_malloc (off);
1340  *buf_length = off;
1341  GNUNET_memcpy (*buf, tmp, off);
1342  if (GNUNET_YES == trc)
1343  return GNUNET_NO;
1344  return GNUNET_OK;
1345 }
1346 
1347 
1355 char *
1357 {
1358  char *ret;
1359  size_t off;
1360  const uint8_t *idata;
1361 
1362  idata = data;
1363  ret = GNUNET_malloc (data_size * 2 + 1);
1364  for (off = 0; off < data_size; off++)
1365  sprintf (&ret[off * 2], "%02x", idata[off]);
1366  return ret;
1367 }
1368 
1369 
1378 size_t
1379 GNUNET_DNSPARSER_hex_to_bin (const char *hex, void *data)
1380 {
1381  size_t data_size;
1382  size_t off;
1383  uint8_t *idata;
1384  unsigned int h;
1385  char in[3];
1386 
1387  data_size = strlen (hex) / 2;
1388  idata = data;
1389  in[2] = '\0';
1390  for (off = 0; off < data_size; off++)
1391  {
1392  in[0] = tolower ((unsigned char) hex[off * 2]);
1393  in[1] = tolower ((unsigned char) hex[off * 2 + 1]);
1394  if (1 != sscanf (in, "%x", &h))
1395  return off;
1396  idata[off] = (uint8_t) h;
1397  }
1398  return off;
1399 }
1400 
1401 
1402 /* end of dnsparser.c */
uint16_t port
TCP or UDP port of the service.
void GNUNET_DNSPARSER_free_soa(struct GNUNET_DNSPARSER_SoaRecord *soa)
Free SOA information record.
Definition: dnsparser.c:119
struct GNUNET_TUN_DnsFlags flags
Flags.
struct GNUNET_DNSPARSER_Record * answers
Array of all answers in the packet, must contain "num_answers" entries.
int GNUNET_DNSPARSER_check_label(const char *label)
Check if a label in UTF-8 format can be coded into valid IDNA.
Definition: dnsparser.c:56
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
Information from SOA records (RFC 1035).
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
static int add_record(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_Record *record)
Add a DNS record to the UDP packet at the given location.
Definition: dnsparser.c:1161
uint32_t retry
Time interval that should elapse before a failed refresh should be retried.
char * GNUNET_DNSPARSER_parse_name(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse name inside of a DNS query or record.
Definition: dnsparser.c:344
uint64_t rel_value_us
The actual value.
uint32_t refresh
Time interval before the zone should be refreshed.
char * mname
The domainname of the name server that was the original or primary source of data for this zone...
Definition: w32nsp.c:83
enum GNUNET_DNSPARSER_CertAlgorithm algorithm
Algorithm.
void GNUNET_DNSPARSER_free_srv(struct GNUNET_DNSPARSER_SrvRecord *srv)
Free SRV information record.
Definition: dnsparser.c:150
#define GNUNET_DNSPARSER_TYPE_CNAME
static char * parse_name(const char *udp_payload, size_t udp_payload_length, size_t *off, unsigned int depth)
Parse name inside of a DNS query or record.
Definition: dnsparser.c:220
char * mxhost
Name of the mail server.
struct GNUNET_DNSPARSER_SrvRecord * srv
SRV data for SRV records.
enum GNUNET_DNSPARSER_CertType cert_type
Certificate type.
uint16_t cert_tag
Certificate KeyTag.
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:245
int GNUNET_DNSPARSER_parse_record(const char *udp_payload, size_t udp_payload_length, size_t *off, struct GNUNET_DNSPARSER_Record *r)
Parse a DNS record entry.
Definition: dnsparser.c:569
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
void GNUNET_DNSPARSER_free_record(struct GNUNET_DNSPARSER_Record *r)
Free the given DNS record.
Definition: dnsparser.c:180
#define GNUNET_TIME_UNIT_SECONDS
One second.
Information from CERT records (RFC 4034).
int GNUNET_DNSPARSER_builder_add_srv(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SrvRecord *srv)
Add an SRV record to the UDP packet at the given location.
Definition: dnsparser.c:1125
DNS query prefix.
uint16_t id
DNS ID (to match replies to requests).
struct GNUNET_DNSPARSER_SoaRecord * GNUNET_DNSPARSER_duplicate_soa_record(const struct GNUNET_DNSPARSER_SoaRecord *r)
Duplicate (deep-copy) the given DNS record.
Definition: dnsparser.c:787
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:854
struct GNUNET_DNSPARSER_CertRecord * GNUNET_DNSPARSER_duplicate_cert_record(const struct GNUNET_DNSPARSER_CertRecord *r)
Duplicate (deep-copy) the given DNS record.
Definition: dnsparser.c:805
#define GNUNET_NO
Definition: gnunet_common.h:81
struct GNUNET_DNSPARSER_SoaRecord * GNUNET_DNSPARSER_parse_soa(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS SOA record.
Definition: dnsparser.c:401
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
Payload of DNS CERT record.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct GNUNET_DNSPARSER_Record * additional_records
Array of all additional answers in the packet, must contain "num_additional_records" entries...
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_DNSPARSER_TYPE_MX
Information from MX records (RFC 1035).
unsigned int num_answers
Number of answers in the packet, should be 0 for queries.
uint16_t dns_traffic_class
Desired class (usually GNUNET_TUN_DNS_CLASS_INTERNET).
uint16_t id
Unique identifier for the request/response.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:94
General DNS record prefix.
uint32_t serial
The version number of the original copy of the zone.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
#define GNUNET_DNSPARSER_TYPE_PTR
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
size_t GNUNET_DNSPARSER_hex_to_bin(const char *hex, void *data)
Convert a HEX string to block of binary data.
Definition: dnsparser.c:1379
uint16_t weight
Relative weight for records with the same priority.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
uint32_t minimum_ttl
The bit minimum TTL field that should be exported with any RR from this zone.
struct GNUNET_DNSPARSER_SrvRecord * GNUNET_DNSPARSER_duplicate_srv_record(const struct GNUNET_DNSPARSER_SrvRecord *r)
Duplicate (deep-copy) the given DNS record.
Definition: dnsparser.c:838
#define GNUNET_DNSPARSER_TYPE_SOA
char * name
Name of the record that the query is for (0-terminated).
char * hostname
For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
#define GNUNET_memcpy(dst, src, n)
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.
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:662
uint16_t port
TCP or UDP port of the service.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_DNSPARSER_TYPE_DNAME
uint16_t type
Record type (GNUNET_DNSPARSER_TYPE_XXX).
char * target
Hostname offering the service.
struct GNUNET_DNSPARSER_CertRecord * GNUNET_DNSPARSER_parse_cert(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS CERT record.
Definition: dnsparser.c:528
uint16_t cert_tag
Certificate KeyTag.
char * rname
A domainname which specifies the mailbox of the person responsible for this zone. ...
uint16_t prio
Preference for this entry (lower value is higher preference).
struct GNUNET_DNSPARSER_SrvRecord * GNUNET_DNSPARSER_parse_srv(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS SRV record.
Definition: dnsparser.c:487
uint8_t algorithm
Algorithm.
static char buf[2048]
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:439
unsigned int message_truncated
Set to 1 if message is truncated.
int GNUNET_DNSPARSER_builder_add_soa(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SoaRecord *soa)
Add an SOA record to the UDP packet at the given location.
Definition: dnsparser.c:1084
uint32_t serial
The version number of the original copy of the zone.
A DNS response record.
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_Record * authority_records
Array of all authority records in the packet, must contain "num_authority_records" entries...
struct GNUNET_DNSPARSER_MxRecord * GNUNET_DNSPARSER_duplicate_mx_record(const struct GNUNET_DNSPARSER_MxRecord *r)
Duplicate (deep-copy) the given DNS record.
Definition: dnsparser.c:822
struct GNUNET_DNSPARSER_Record * GNUNET_DNSPARSER_duplicate_record(const struct GNUNET_DNSPARSER_Record *r)
Duplicate (deep-copy) the given DNS record.
Definition: dnsparser.c:743
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.
struct GNUNET_DNSPARSER_MxRecord * GNUNET_DNSPARSER_parse_mx(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS MX record.
Definition: dnsparser.c:446
int GNUNET_DNSPARSER_builder_add_cert(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_CertRecord *cert)
Add a CERT record to the UDP packet at the given location.
Definition: dnsparser.c:1037
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
int GNUNET_DNSPARSER_parse_query(const char *udp_payload, size_t udp_payload_length, size_t *off, struct GNUNET_DNSPARSER_Query *q)
Parse a DNS query entry.
Definition: dnsparser.c:363
uint16_t cert_type
Certificate type.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
size_t data_len
Number of bytes in data.
uint16_t query_count
Number of queries.
void * data
Binary record data.
int GNUNET_DNSPARSER_builder_add_mx(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_MxRecord *mx)
Add an MX record to the UDP packet at the given location.
Definition: dnsparser.c:1008
const char * name
int GNUNET_DNSPARSER_check_name(const char *name)
Check if a label in UTF-8 format can be coded into valid IDNA.
Definition: dnsparser.c:86
uint32_t refresh
Time interval before the zone should be refreshed.
unsigned int num_authority_records
Number of authoritative answers in the packet, should be 0 for queries.
uint16_t authority_rcount
Number of authoritative answers.
struct GNUNET_TIME_Absolute expiration_time
When does the record expire?
Payload of DNS SRV record (header).
size_t certificate_size
Number of bytes in certificate_data.
uint16_t data_len
Number of bytes of data that follow.
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
#define GNUNET_DNSPARSER_TYPE_NS
void GNUNET_DNSPARSER_free_cert(struct GNUNET_DNSPARSER_CertRecord *cert)
Free CERT information record.
Definition: dnsparser.c:135
uint16_t answer_rcount
Number of answers.
Easy-to-process, parsed version of a DNS packet.
#define GNUNET_log(kind,...)
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
uint16_t additional_rcount
Number of additional records.
uint16_t priority
Preference for this entry (lower value is higher preference).
char * name
Name of the record that the query is for (0-terminated).
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:331
Payload of DNS SOA record (header).
unsigned int num_queries
Number of queries in the packet.
int GNUNET_DNSPARSER_builder_add_query(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_Query *query)
Add a DNS query to the UDP packet at the given location.
Definition: dnsparser.c:971
uint16_t weight
Relative weight for records with the same priority.
#define GNUNET_YES
Definition: gnunet_common.h:80
uint32_t minimum
The bit minimum TTL field that should be exported with any RR from this zone.
char * certificate_data
Data of the certificate.
uint32_t ttl
Expiration for the record (in seconds).
union GNUNET_DNSPARSER_Record::@27 data
Payload of the record (which one of these is valid depends on the &#39;type&#39;).
struct GNUNET_TUN_DnsFlags flags
Bitfield of DNS flags.
int GNUNET_DNSPARSER_builder_add_name(char *dst, size_t dst_len, size_t *off, const char *name)
Add a DNS name to the UDP packet at the given location, converting the name to IDNA notation as neces...
Definition: dnsparser.c:889
#define GNUNET_DNSPARSER_TYPE_SRV
uint32_t data
The data value.
uint16_t preference
Preference for this entry (lower value is higher preference).
static size_t data_size
Number of bytes in data.
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
void GNUNET_DNSPARSER_free_mx(struct GNUNET_DNSPARSER_MxRecord *mx)
Free MX information record.
Definition: dnsparser.c:165
#define GNUNET_DNSPARSER_TYPE_CERT
uint16_t dns_traffic_class
Record class (usually GNUNET_TUN_DNS_CLASS_INTERNET).
#define GNUNET_malloc(size)
Wrapper around malloc.
uint16_t type
Desired type (GNUNET_DNSPARSER_TYPE_XXX).
struct GNUNET_DNSPARSER_CertRecord * cert
CERT data for CERT records.
char * GNUNET_DNSPARSER_bin_to_hex(const void *data, size_t data_size)
Convert a block of binary data to HEX.
Definition: dnsparser.c:1356
Information from SRV records (RFC 2782).
#define GNUNET_free(ptr)
Wrapper around free.
uint32_t retry
Time interval that should elapse before a failed refresh should be retried.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...