GNUnet  0.11.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 #include "gnunet_util_lib.h"
42 
43 
52 int
53 GNUNET_DNSPARSER_check_label (const char *label)
54 {
55  char *output;
56  size_t slen;
57 
58  if (NULL != strchr (label, '.'))
59  return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */
60  if (0 == strcmp (label, "@")) /* '@' is reserved for the empty label, see #GNUNET_GNS_EMPTY_LABEL_AT */
61  return GNUNET_SYSERR;
62  if (IDNA_SUCCESS != idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED))
63  return GNUNET_SYSERR;
64  slen = strlen (output);
65  free (output);
66  return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK;
67 }
68 
69 
78 int
80 {
81  char *ldup;
82  char *output;
83  size_t slen;
84  char *tok;
85 
86  ldup = GNUNET_strdup (name);
87  for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, "."))
89  {
90  GNUNET_free (ldup);
91  return GNUNET_SYSERR;
92  }
93  GNUNET_free (ldup);
94  if (IDNA_SUCCESS != idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED))
95  return GNUNET_SYSERR;
96  slen = strlen (output);
97  free (output);
98  return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK;
99 }
100 
101 
107 void
109 {
110  if (NULL == soa)
111  return;
114  GNUNET_free (soa);
115 }
116 
117 
123 void
125 {
126  if (NULL == cert)
127  return;
129  GNUNET_free (cert);
130 }
131 
132 
138 void
140 {
141  if (NULL == srv)
142  return;
144  GNUNET_free (srv);
145 }
146 
147 
153 void
155 {
156  if (NULL == mx)
157  return;
159  GNUNET_free (mx);
160 }
161 
162 
168 void
170 {
172  switch (r->type)
173  {
176  break;
177 
180  break;
181 
184  break;
185 
188  break;
189 
194  break;
195 
196  default:
198  break;
199  }
200 }
201 
202 
213 static char *
214 parse_name (const char *udp_payload,
215  size_t udp_payload_length,
216  size_t *off,
217  unsigned int depth)
218 {
219  const uint8_t *input = (const uint8_t *) udp_payload;
220  char *ret;
221  char *tmp;
222  char *xstr;
223  uint8_t len;
224  size_t xoff;
225  char *utf8;
226  Idna_rc rc;
227 
228  ret = GNUNET_strdup ("");
229  while (1)
230  {
231  if (*off >= udp_payload_length)
232  {
233  GNUNET_break_op (0);
234  goto error;
235  }
236  len = input[*off];
237  if (0 == len)
238  {
239  (*off)++;
240  break;
241  }
242  if (len < 64)
243  {
244  if (*off + 1 + len > udp_payload_length)
245  {
246  GNUNET_break_op (0);
247  goto error;
248  }
249  GNUNET_asprintf (&tmp, "%.*s", (int) len, &udp_payload[*off + 1]);
250  if (IDNA_SUCCESS !=
251  (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED)))
252  {
254  _ ("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
255  tmp,
256  idna_strerror (rc));
257  GNUNET_free (tmp);
258  GNUNET_asprintf (&tmp,
259  "%s%.*s.",
260  ret,
261  (int) len,
262  &udp_payload[*off + 1]);
263  }
264  else
265  {
266  GNUNET_free (tmp);
267  GNUNET_asprintf (&tmp, "%s%s.", ret, utf8);
268  free (utf8);
269  }
270  GNUNET_free (ret);
271  ret = tmp;
272  *off += 1 + len;
273  }
274  else if ((64 | 128) == (len & (64 | 128)))
275  {
276  if (depth > 32)
277  {
278  GNUNET_break_op (0);
279  goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */
280  }
281  /* pointer to string */
282  if (*off + 1 > udp_payload_length)
283  {
284  GNUNET_break_op (0);
285  goto error;
286  }
287  xoff = ((len - (64 | 128)) << 8) + input[*off + 1];
288  xstr = parse_name (udp_payload, udp_payload_length, &xoff, depth + 1);
289  if (NULL == xstr)
290  {
291  GNUNET_break_op (0);
292  goto error;
293  }
294  GNUNET_asprintf (&tmp, "%s%s.", ret, xstr);
295  GNUNET_free (ret);
296  GNUNET_free (xstr);
297  ret = tmp;
298  if (strlen (ret) > udp_payload_length)
299  {
300  GNUNET_break_op (0);
301  goto error; /* we are looping (building an infinite string) */
302  }
303  *off += 2;
304  /* pointers always terminate names */
305  break;
306  }
307  else
308  {
309  /* neither pointer nor inline string, not supported... */
310  GNUNET_break_op (0);
311  goto error;
312  }
313  }
314  if (0 < strlen (ret))
315  ret[strlen (ret) - 1] = '\0'; /* eat tailing '.' */
316  return ret;
317 error:
318  GNUNET_break_op (0);
319  GNUNET_free (ret);
320  return NULL;
321 }
322 
323 
333 char *
334 GNUNET_DNSPARSER_parse_name (const char *udp_payload,
335  size_t udp_payload_length,
336  size_t *off)
337 {
338  return parse_name (udp_payload, udp_payload_length, off, 0);
339 }
340 
341 
352 int
353 GNUNET_DNSPARSER_parse_query (const char *udp_payload,
354  size_t udp_payload_length,
355  size_t *off,
356  struct GNUNET_DNSPARSER_Query *q)
357 {
358  char *name;
359  struct GNUNET_TUN_DnsQueryLine ql;
360 
361  name = GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
362  if (NULL == name)
363  {
364  GNUNET_break_op (0);
365  return GNUNET_SYSERR;
366  }
367  q->name = name;
368  if (*off + sizeof(struct GNUNET_TUN_DnsQueryLine) > udp_payload_length)
369  {
370  GNUNET_break_op (0);
371  return GNUNET_SYSERR;
372  }
373  GNUNET_memcpy (&ql, &udp_payload[*off], sizeof(ql));
374  *off += sizeof(ql);
375  q->type = ntohs (ql.type);
376  q->dns_traffic_class = ntohs (ql.dns_traffic_class);
377  return GNUNET_OK;
378 }
379 
380 
391 GNUNET_DNSPARSER_parse_soa (const char *udp_payload,
392  size_t udp_payload_length,
393  size_t *off)
394 {
395  struct GNUNET_DNSPARSER_SoaRecord *soa;
396  struct GNUNET_TUN_DnsSoaRecord soa_bin;
397  size_t old_off;
398 
399  old_off = *off;
400  soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord);
401  soa->mname =
402  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
403  soa->rname =
404  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
405  if ((NULL == soa->mname) || (NULL == soa->rname) ||
406  (*off + sizeof(struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length))
407  {
408  GNUNET_break_op (0);
410  *off = old_off;
411  return NULL;
412  }
413  GNUNET_memcpy (&soa_bin,
414  &udp_payload[*off],
415  sizeof(struct GNUNET_TUN_DnsSoaRecord));
416  soa->serial = ntohl (soa_bin.serial);
417  soa->refresh = ntohl (soa_bin.refresh);
418  soa->retry = ntohl (soa_bin.retry);
419  soa->expire = ntohl (soa_bin.expire);
420  soa->minimum_ttl = ntohl (soa_bin.minimum);
421  (*off) += sizeof(struct GNUNET_TUN_DnsSoaRecord);
422  return soa;
423 }
424 
425 
436 GNUNET_DNSPARSER_parse_mx (const char *udp_payload,
437  size_t udp_payload_length,
438  size_t *off)
439 {
440  struct GNUNET_DNSPARSER_MxRecord *mx;
441  uint16_t mxpref;
442  size_t old_off;
443 
444  old_off = *off;
445  if (*off + sizeof(uint16_t) > udp_payload_length)
446  {
447  GNUNET_break_op (0);
448  return NULL;
449  }
450  GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof(uint16_t));
451  (*off) += sizeof(uint16_t);
453  mx->preference = ntohs (mxpref);
454  mx->mxhost =
455  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
456  if (NULL == mx->mxhost)
457  {
458  GNUNET_break_op (0);
460  *off = old_off;
461  return NULL;
462  }
463  return mx;
464 }
465 
466 
477 GNUNET_DNSPARSER_parse_srv (const char *udp_payload,
478  size_t udp_payload_length,
479  size_t *off)
480 {
481  struct GNUNET_DNSPARSER_SrvRecord *srv;
482  struct GNUNET_TUN_DnsSrvRecord srv_bin;
483  size_t old_off;
484 
485  old_off = *off;
486  if (*off + sizeof(struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length)
487  return NULL;
488  GNUNET_memcpy (&srv_bin,
489  &udp_payload[*off],
490  sizeof(struct GNUNET_TUN_DnsSrvRecord));
491  (*off) += sizeof(struct GNUNET_TUN_DnsSrvRecord);
492  srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord);
493  srv->priority = ntohs (srv_bin.prio);
494  srv->weight = ntohs (srv_bin.weight);
495  srv->port = ntohs (srv_bin.port);
496  srv->target =
497  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
498  if (NULL == srv->target)
499  {
501  *off = old_off;
502  return NULL;
503  }
504  return srv;
505 }
506 
507 
518 GNUNET_DNSPARSER_parse_cert (const char *udp_payload,
519  size_t udp_payload_length,
520  size_t *off)
521 {
522  struct GNUNET_DNSPARSER_CertRecord *cert;
523  struct GNUNET_TUN_DnsCertRecord dcert;
524 
525  if (*off + sizeof(struct GNUNET_TUN_DnsCertRecord) >= udp_payload_length)
526  {
527  GNUNET_break_op (0);
528  return NULL;
529  }
530  GNUNET_memcpy (&dcert,
531  &udp_payload[*off],
532  sizeof(struct GNUNET_TUN_DnsCertRecord));
533  (*off) += sizeof(struct GNUNET_TUN_DnsCertRecord);
534  cert = GNUNET_new (struct GNUNET_DNSPARSER_CertRecord);
535  cert->cert_type = ntohs (dcert.cert_type);
536  cert->cert_tag = ntohs (dcert.cert_tag);
537  cert->algorithm = dcert.algorithm;
538  cert->certificate_size = udp_payload_length - (*off);
541  &udp_payload[*off],
542  cert->certificate_size);
543  (*off) += cert->certificate_size;
544  return cert;
545 }
546 
547 
558 int
559 GNUNET_DNSPARSER_parse_record (const char *udp_payload,
560  size_t udp_payload_length,
561  size_t *off,
562  struct GNUNET_DNSPARSER_Record *r)
563 {
564  char *name;
565  struct GNUNET_TUN_DnsRecordLine rl;
566  size_t old_off;
567  uint16_t data_len;
568 
569  name = GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
570  if (NULL == name)
571  {
572  GNUNET_break_op (0);
573  return GNUNET_SYSERR;
574  }
575  r->name = name;
576  if (*off + sizeof(struct GNUNET_TUN_DnsRecordLine) > udp_payload_length)
577  {
578  GNUNET_break_op (0);
579  return GNUNET_SYSERR;
580  }
581  GNUNET_memcpy (&rl, &udp_payload[*off], sizeof(rl));
582  (*off) += sizeof(rl);
583  r->type = ntohs (rl.type);
584  r->dns_traffic_class = ntohs (rl.dns_traffic_class);
587  data_len = ntohs (rl.data_len);
588  if (*off + data_len > udp_payload_length)
589  {
590  GNUNET_break_op (0);
591  return GNUNET_SYSERR;
592  }
593  old_off = *off;
594  switch (r->type)
595  {
600  r->data.hostname =
601  GNUNET_DNSPARSER_parse_name (udp_payload, udp_payload_length, off);
602  if ((NULL == r->data.hostname) || (old_off + data_len != *off))
603  return GNUNET_SYSERR;
604  return GNUNET_OK;
605 
607  r->data.soa =
608  GNUNET_DNSPARSER_parse_soa (udp_payload, udp_payload_length, off);
609  if ((NULL == r->data.soa) || (old_off + data_len != *off))
610  {
611  GNUNET_break_op (0);
612  return GNUNET_SYSERR;
613  }
614  return GNUNET_OK;
615 
617  r->data.mx =
618  GNUNET_DNSPARSER_parse_mx (udp_payload, udp_payload_length, off);
619  if ((NULL == r->data.mx) || (old_off + data_len != *off))
620  {
621  GNUNET_break_op (0);
622  return GNUNET_SYSERR;
623  }
624  return GNUNET_OK;
625 
627  r->data.srv =
628  GNUNET_DNSPARSER_parse_srv (udp_payload, udp_payload_length, off);
629  if ((NULL == r->data.srv) || (old_off + data_len != *off))
630  {
631  GNUNET_break_op (0);
632  return GNUNET_SYSERR;
633  }
634  return GNUNET_OK;
635 
636  default:
637  r->data.raw.data = GNUNET_malloc (data_len);
638  r->data.raw.data_len = data_len;
639  GNUNET_memcpy (r->data.raw.data, &udp_payload[*off], data_len);
640  break;
641  }
642  (*off) += data_len;
643  return GNUNET_OK;
644 }
645 
646 
656 GNUNET_DNSPARSER_parse (const char *udp_payload, size_t udp_payload_length)
657 {
658  struct GNUNET_DNSPARSER_Packet *p;
659  const struct GNUNET_TUN_DnsHeader *dns;
660  size_t off;
661  unsigned int n;
662 
663  if (udp_payload_length < sizeof(struct GNUNET_TUN_DnsHeader))
664  return NULL;
665  dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload;
666  off = sizeof(struct GNUNET_TUN_DnsHeader);
667  p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
668  p->flags = dns->flags;
669  p->id = dns->id;
670  n = ntohs (dns->query_count);
671  if (n > 0)
672  {
674  p->num_queries = n;
675  for (unsigned int i = 0; i < n; i++)
676  if (GNUNET_OK != GNUNET_DNSPARSER_parse_query (udp_payload,
677  udp_payload_length,
678  &off,
679  &p->queries[i]))
680  goto error;
681  }
682  n = ntohs (dns->answer_rcount);
683  if (n > 0)
684  {
686  p->num_answers = n;
687  for (unsigned int i = 0; i < n; i++)
688  if (GNUNET_OK != GNUNET_DNSPARSER_parse_record (udp_payload,
689  udp_payload_length,
690  &off,
691  &p->answers[i]))
692  goto error;
693  }
694  n = ntohs (dns->authority_rcount);
695  if (n > 0)
696  {
698  p->num_authority_records = n;
699  for (unsigned int i = 0; i < n; i++)
700  if (GNUNET_OK != GNUNET_DNSPARSER_parse_record (udp_payload,
701  udp_payload_length,
702  &off,
703  &p->authority_records[i]))
704  goto error;
705  }
706  n = ntohs (dns->additional_rcount);
707  if (n > 0)
708  {
709  p->additional_records =
711  p->num_additional_records = n;
712  for (unsigned int i = 0; i < n; i++)
713  {
714  if (GNUNET_OK !=
715  GNUNET_DNSPARSER_parse_record (udp_payload,
716  udp_payload_length,
717  &off,
718  &p->additional_records[i]))
719  goto error;
720  }
721  }
722  return p;
723 error:
724  GNUNET_break_op (0);
726  return NULL;
727 }
728 
729 
738 {
739  struct GNUNET_DNSPARSER_Record *dup = GNUNET_memdup (r, sizeof(*r));
740 
741  dup->name = GNUNET_strdup (r->name);
742  switch (r->type)
743  {
748  break;
749  }
750 
753  break;
754  }
755 
758  break;
759  }
760 
763  break;
764  }
765 
768  break;
769  }
770 
771  default: {
772  dup->data.raw.data = GNUNET_memdup (r->data.raw.data,
773  r->data.raw.data_len);
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  }
940  while (NULL != dot);
941  dst[pos++] = '\0'; /* terminator */
942  *off = pos;
943  free (idna_start);
944  return GNUNET_OK;
945 fail:
946  free (idna_start);
947  return GNUNET_NO;
948 }
949 
950 
963 int
965  size_t dst_len,
966  size_t *off,
967  const struct GNUNET_DNSPARSER_Query *query)
968 {
969  int ret;
970  struct GNUNET_TUN_DnsQueryLine ql;
971 
973  dst_len
974  - sizeof(
975  struct GNUNET_TUN_DnsQueryLine),
976  off,
977  query->name);
978  if (ret != GNUNET_OK)
979  return ret;
980  ql.type = htons (query->type);
981  ql.dns_traffic_class = htons (query->dns_traffic_class);
982  GNUNET_memcpy (&dst[*off], &ql, sizeof(ql));
983  (*off) += sizeof(ql);
984  return GNUNET_OK;
985 }
986 
987 
1000 int
1002  size_t dst_len,
1003  size_t *off,
1004  const struct GNUNET_DNSPARSER_MxRecord *mx)
1005 {
1006  uint16_t mxpref;
1007 
1008  if (*off + sizeof(uint16_t) > dst_len)
1009  return GNUNET_NO;
1010  mxpref = htons (mx->preference);
1011  GNUNET_memcpy (&dst[*off], &mxpref, sizeof(mxpref));
1012  (*off) += sizeof(mxpref);
1013  return GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, mx->mxhost);
1014 }
1015 
1016 
1029 int
1031  char *dst,
1032  size_t dst_len,
1033  size_t *off,
1034  const struct GNUNET_DNSPARSER_CertRecord *cert)
1035 {
1036  struct GNUNET_TUN_DnsCertRecord dcert;
1037 
1038 #ifdef __clang__
1039 #pragma clang diagnostic push
1040 #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
1041 #endif
1042  if ((cert->cert_type > UINT16_MAX) || (cert->algorithm > UINT8_MAX))
1043  {
1044  GNUNET_break (0);
1045  return GNUNET_SYSERR;
1046  }
1047 #ifdef __clang__
1048 #pragma clang diagnostic pop
1049 #endif
1050  if (*off + sizeof(struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size >
1051  dst_len)
1052  return GNUNET_NO;
1053  dcert.cert_type = htons ((uint16_t) cert->cert_type);
1054  dcert.cert_tag = htons ((uint16_t) cert->cert_tag);
1055  dcert.algorithm = (uint8_t) cert->algorithm;
1056  GNUNET_memcpy (&dst[*off], &dcert, sizeof(dcert));
1057  (*off) += sizeof(dcert);
1058  GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size);
1059  (*off) += cert->certificate_size;
1060  return GNUNET_OK;
1061 }
1062 
1063 
1076 int
1078  size_t dst_len,
1079  size_t *off,
1080  const struct GNUNET_DNSPARSER_SoaRecord *soa)
1081 {
1082  struct GNUNET_TUN_DnsSoaRecord sd;
1083  int ret;
1084 
1085  if ((GNUNET_OK !=
1086  (ret =
1087  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->mname))) ||
1088  (GNUNET_OK !=
1089  (ret =
1090  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->rname))))
1091  return ret;
1092  if (*off + sizeof(struct GNUNET_TUN_DnsSoaRecord) > dst_len)
1093  return GNUNET_NO;
1094  sd.serial = htonl (soa->serial);
1095  sd.refresh = htonl (soa->refresh);
1096  sd.retry = htonl (soa->retry);
1097  sd.expire = htonl (soa->expire);
1098  sd.minimum = htonl (soa->minimum_ttl);
1099  GNUNET_memcpy (&dst[*off], &sd, sizeof(sd));
1100  (*off) += sizeof(sd);
1101  return GNUNET_OK;
1102 }
1103 
1104 
1117 int
1119  size_t dst_len,
1120  size_t *off,
1121  const struct GNUNET_DNSPARSER_SrvRecord *srv)
1122 {
1123  struct GNUNET_TUN_DnsSrvRecord sd;
1124  int ret;
1125 
1126  if (*off + sizeof(struct GNUNET_TUN_DnsSrvRecord) > dst_len)
1127  return GNUNET_NO;
1128  sd.prio = htons (srv->priority);
1129  sd.weight = htons (srv->weight);
1130  sd.port = htons (srv->port);
1131  GNUNET_memcpy (&dst[*off], &sd, sizeof(sd));
1132  (*off) += sizeof(sd);
1133  if (GNUNET_OK !=
1134  (ret =
1135  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, srv->target)))
1136  return ret;
1137  return GNUNET_OK;
1138 }
1139 
1140 
1153 static int
1154 add_record (char *dst,
1155  size_t dst_len,
1156  size_t *off,
1157  const struct GNUNET_DNSPARSER_Record *record)
1158 {
1159  int ret;
1160  size_t start;
1161  size_t pos;
1162  struct GNUNET_TUN_DnsRecordLine rl;
1163 
1164  start = *off;
1166  dst_len
1167  - sizeof(
1168  struct GNUNET_TUN_DnsRecordLine),
1169  off,
1170  record->name);
1171  if (GNUNET_OK != ret)
1172  return ret;
1173  /* '*off' is now the position where we will need to write the record line */
1174 
1175  pos = *off + sizeof(struct GNUNET_TUN_DnsRecordLine);
1176  switch (record->type)
1177  {
1179  ret = GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &pos, record->data.mx);
1180  break;
1181 
1183  ret =
1184  GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &pos, record->data.cert);
1185  break;
1186 
1188  ret =
1189  GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &pos, record->data.soa);
1190  break;
1191 
1196  dst_len,
1197  &pos,
1198  record->data.hostname);
1199  break;
1200 
1202  ret =
1203  GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &pos, record->data.srv);
1204  break;
1205 
1206  default:
1207  if (pos + record->data.raw.data_len > dst_len)
1208  {
1209  ret = GNUNET_NO;
1210  break;
1211  }
1212  GNUNET_memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
1213  pos += record->data.raw.data_len;
1214  ret = GNUNET_OK;
1215  break;
1216  }
1217  if (GNUNET_OK != ret)
1218  {
1219  *off = start;
1220  return GNUNET_NO;
1221  }
1222 
1223  if (pos - (*off + sizeof(struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX)
1224  {
1225  /* record data too long */
1226  *off = start;
1227  return GNUNET_NO;
1228  }
1229  rl.type = htons (record->type);
1230  rl.dns_traffic_class = htons (record->dns_traffic_class);
1231  rl.ttl = htonl (
1233  / 1000LL / 1000LL); /* in seconds */
1234  rl.data_len = htons (
1235  (uint16_t) (pos - (*off + sizeof(struct GNUNET_TUN_DnsRecordLine))));
1236  GNUNET_memcpy (&dst[*off], &rl, sizeof(struct GNUNET_TUN_DnsRecordLine));
1237  *off = pos;
1238  return GNUNET_OK;
1239 }
1240 
1241 
1256 int
1258  uint16_t max,
1259  char **buf,
1260  size_t *buf_length)
1261 {
1262  struct GNUNET_TUN_DnsHeader dns;
1263  size_t off;
1264  char tmp[max];
1265  int ret;
1266  int trc;
1267 
1268  if ((p->num_queries > UINT16_MAX) || (p->num_answers > UINT16_MAX) ||
1269  (p->num_authority_records > UINT16_MAX) ||
1270  (p->num_additional_records > UINT16_MAX))
1271  return GNUNET_SYSERR;
1272  dns.id = p->id;
1273  dns.flags = p->flags;
1274  dns.query_count = htons (p->num_queries);
1275  dns.answer_rcount = htons (p->num_answers);
1276  dns.authority_rcount = htons (p->num_authority_records);
1277  dns.additional_rcount = htons (p->num_additional_records);
1278 
1279  off = sizeof(struct GNUNET_TUN_DnsHeader);
1280  trc = GNUNET_NO;
1281  for (unsigned int i = 0; i < p->num_queries; i++)
1282  {
1284  sizeof(tmp),
1285  &off,
1286  &p->queries[i]);
1287  if (GNUNET_SYSERR == ret)
1288  return GNUNET_SYSERR;
1289  if (GNUNET_NO == ret)
1290  {
1291  dns.query_count = htons ((uint16_t) (i - 1));
1292  trc = GNUNET_YES;
1293  break;
1294  }
1295  }
1296  for (unsigned int i = 0; i < p->num_answers; i++)
1297  {
1298  ret = add_record (tmp, sizeof(tmp), &off, &p->answers[i]);
1299  if (GNUNET_SYSERR == ret)
1300  return GNUNET_SYSERR;
1301  if (GNUNET_NO == ret)
1302  {
1303  dns.answer_rcount = htons ((uint16_t) (i - 1));
1304  trc = GNUNET_YES;
1305  break;
1306  }
1307  }
1308  for (unsigned int i = 0; i < p->num_authority_records; i++)
1309  {
1310  ret = add_record (tmp, sizeof(tmp), &off, &p->authority_records[i]);
1311  if (GNUNET_SYSERR == ret)
1312  return GNUNET_SYSERR;
1313  if (GNUNET_NO == ret)
1314  {
1315  dns.authority_rcount = htons ((uint16_t) (i - 1));
1316  trc = GNUNET_YES;
1317  break;
1318  }
1319  }
1320  for (unsigned int i = 0; i < p->num_additional_records; i++)
1321  {
1322  ret = add_record (tmp, sizeof(tmp), &off, &p->additional_records[i]);
1323  if (GNUNET_SYSERR == ret)
1324  return GNUNET_SYSERR;
1325  if (GNUNET_NO == ret)
1326  {
1327  dns.additional_rcount = htons (i - 1);
1328  trc = GNUNET_YES;
1329  break;
1330  }
1331  }
1332 
1333  if (GNUNET_YES == trc)
1334  dns.flags.message_truncated = 1;
1335  GNUNET_memcpy (tmp, &dns, sizeof(struct GNUNET_TUN_DnsHeader));
1336 
1337  *buf = GNUNET_malloc (off);
1338  *buf_length = off;
1339  GNUNET_memcpy (*buf, tmp, off);
1340  if (GNUNET_YES == trc)
1341  return GNUNET_NO;
1342  return GNUNET_OK;
1343 }
1344 
1345 
1353 char *
1355 {
1356  char *ret;
1357  size_t off;
1358  const uint8_t *idata;
1359 
1360  idata = data;
1361  ret = GNUNET_malloc (data_size * 2 + 1);
1362  for (off = 0; off < data_size; off++)
1363  sprintf (&ret[off * 2], "%02x", idata[off]);
1364  return ret;
1365 }
1366 
1367 
1376 size_t
1377 GNUNET_DNSPARSER_hex_to_bin (const char *hex, void *data)
1378 {
1379  size_t data_size;
1380  size_t off;
1381  uint8_t *idata;
1382  unsigned int h;
1383  char in[3];
1384 
1385  data_size = strlen (hex) / 2;
1386  idata = data;
1387  in[2] = '\0';
1388  for (off = 0; off < data_size; off++)
1389  {
1390  in[0] = tolower ((unsigned char) hex[off * 2]);
1391  in[1] = tolower ((unsigned char) hex[off * 2 + 1]);
1392  if (1 != sscanf (in, "%x", &h))
1393  return off;
1394  idata[off] = (uint8_t) h;
1395  }
1396  return off;
1397 }
1398 
1399 
1400 /* 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:108
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:53
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:1154
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:334
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...
enum GNUNET_DNSPARSER_CertAlgorithm algorithm
Algorithm.
void GNUNET_DNSPARSER_free_srv(struct GNUNET_DNSPARSER_SrvRecord *srv)
Free SRV information record.
Definition: dnsparser.c:139
#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:214
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:246
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
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:559
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
void GNUNET_DNSPARSER_free_record(struct GNUNET_DNSPARSER_Record *r)
Free the given DNS record.
Definition: dnsparser.c:169
#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:1118
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
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
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:78
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:391
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#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...
#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:99
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:181
#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:1377
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.
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:656
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:518
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:477
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.
union GNUNET_DNSPARSER_Record::@24 data
Payload of the record (which one of these is valid depends on the &#39;type&#39;).
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:442
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:1077
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:737
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:436
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:1030
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:353
uint16_t cert_type
Certificate type.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
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:1001
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:79
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
const char * name
void GNUNET_DNSPARSER_free_cert(struct GNUNET_DNSPARSER_CertRecord *cert)
Free CERT information record.
Definition: dnsparser.c:124
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.
static void record(void *cls, size_t data_size, const void *data)
Process recorded audio data.
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:964
uint16_t weight
Relative weight for records with the same priority.
#define GNUNET_YES
Definition: gnunet_common.h:77
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).
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).
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:154
#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:1354
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...