GNUnet  0.19.4
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 
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #if HAVE_LIBIDN2
31 #if HAVE_IDN2_H
32 #include <idn2.h>
33 #elif HAVE_IDN2_IDN2_H
34 #include <idn2/idn2.h>
35 #endif
36 #elif HAVE_LIBIDN
37 #if HAVE_IDNA_H
38 #include <idna.h>
39 #elif HAVE_IDN_IDNA_H
40 #include <idn/idna.h>
41 #endif
42 #endif
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;
112  GNUNET_free (soa->mname);
113  GNUNET_free (soa->rname);
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;
143  GNUNET_free (srv->target);
144  GNUNET_free (srv);
145 }
146 
147 
153 void
155 {
156  if (NULL == mx)
157  return;
158  GNUNET_free (mx->mxhost);
159  GNUNET_free (mx);
160 }
161 
162 
168 void
170 {
171  GNUNET_free (r->name);
172  switch (r->type)
173  {
176  break;
177 
180  break;
181 
184  break;
185 
188  break;
189 
194  break;
195 
196  default:
197  GNUNET_free (r->data.raw.data);
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:
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);
668  p->flags = dns->flags;
669  p->id = dns->id;
670  n = ntohs (dns->query_count);
671  if (n > 0)
672  {
673  p->queries = GNUNET_new_array (n, struct GNUNET_DNSPARSER_Query);
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  {
685  p->answers = GNUNET_new_array (n, struct GNUNET_DNSPARSER_Record);
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  {
697  p->authority_records = GNUNET_new_array (n, struct GNUNET_DNSPARSER_Record);
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++)
857  GNUNET_free (p->queries[i].name);
858  GNUNET_free (p->queries);
859  for (unsigned int i = 0; i < p->num_answers; i++)
860  GNUNET_DNSPARSER_free_record (&p->answers[i]);
861  GNUNET_free (p->answers);
862  for (unsigned int i = 0; i < p->num_authority_records; i++)
863  GNUNET_DNSPARSER_free_record (&p->authority_records[i]);
864  GNUNET_free (p->authority_records);
865  for (unsigned int i = 0; i < p->num_additional_records; i++)
866  GNUNET_DNSPARSER_free_record (&p->additional_records[i]);
867  GNUNET_free (p->additional_records);
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 == 0)
928  break;
929  if (len >= 64)
930  {
932  "Invalid DNS name `%s': label with %u characters encountered\n",
933  name,
934  (unsigned int) len);
935  goto fail; /* label too long or empty */
936  }
937  dst[pos++] = (char) (uint8_t) len;
938  GNUNET_memcpy (&dst[pos], idna_name, len);
939  pos += len;
940  idna_name += len + 1; /* also skip dot */
941  }
942  while (NULL != dot);
943  dst[pos++] = '\0'; /* terminator */
944  *off = pos;
945  free (idna_start);
946  return GNUNET_OK;
947 fail:
948  free (idna_start);
949  return GNUNET_NO;
950 }
951 
952 
965 int
967  size_t dst_len,
968  size_t *off,
969  const struct GNUNET_DNSPARSER_Query *query)
970 {
971  int ret;
972  struct GNUNET_TUN_DnsQueryLine ql;
973 
975  dst_len
976  - sizeof(
977  struct GNUNET_TUN_DnsQueryLine),
978  off,
979  query->name);
980  if (ret != GNUNET_OK)
981  return ret;
982  ql.type = htons (query->type);
983  ql.dns_traffic_class = htons (query->dns_traffic_class);
984  GNUNET_memcpy (&dst[*off], &ql, sizeof(ql));
985  (*off) += sizeof(ql);
986  return GNUNET_OK;
987 }
988 
989 
1002 int
1004  size_t dst_len,
1005  size_t *off,
1006  const struct GNUNET_DNSPARSER_MxRecord *mx)
1007 {
1008  uint16_t mxpref;
1009 
1010  if (*off + sizeof(uint16_t) > dst_len)
1011  return GNUNET_NO;
1012  mxpref = htons (mx->preference);
1013  GNUNET_memcpy (&dst[*off], &mxpref, sizeof(mxpref));
1014  (*off) += sizeof(mxpref);
1015  return GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, mx->mxhost);
1016 }
1017 
1018 
1031 int
1033  char *dst,
1034  size_t dst_len,
1035  size_t *off,
1036  const struct GNUNET_DNSPARSER_CertRecord *cert)
1037 {
1038  struct GNUNET_TUN_DnsCertRecord dcert;
1039 
1040 #ifdef __clang__
1041 #pragma clang diagnostic push
1042 #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
1043 #endif
1044  if ((cert->cert_type > UINT16_MAX) || (cert->algorithm > UINT8_MAX))
1045  {
1046  GNUNET_break (0);
1047  return GNUNET_SYSERR;
1048  }
1049 #ifdef __clang__
1050 #pragma clang diagnostic pop
1051 #endif
1052  if (*off + sizeof(struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size >
1053  dst_len)
1054  return GNUNET_NO;
1055  dcert.cert_type = htons ((uint16_t) cert->cert_type);
1056  dcert.cert_tag = htons ((uint16_t) cert->cert_tag);
1057  dcert.algorithm = (uint8_t) cert->algorithm;
1058  GNUNET_memcpy (&dst[*off], &dcert, sizeof(dcert));
1059  (*off) += sizeof(dcert);
1060  GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size);
1061  (*off) += cert->certificate_size;
1062  return GNUNET_OK;
1063 }
1064 
1065 
1078 int
1080  size_t dst_len,
1081  size_t *off,
1082  const struct GNUNET_DNSPARSER_SoaRecord *soa)
1083 {
1084  struct GNUNET_TUN_DnsSoaRecord sd;
1085  int ret;
1086 
1087  if ((GNUNET_OK !=
1088  (ret =
1089  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->mname))) ||
1090  (GNUNET_OK !=
1091  (ret =
1092  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, soa->rname))))
1093  return ret;
1094  if (*off + sizeof(struct GNUNET_TUN_DnsSoaRecord) > dst_len)
1095  return GNUNET_NO;
1096  sd.serial = htonl (soa->serial);
1097  sd.refresh = htonl (soa->refresh);
1098  sd.retry = htonl (soa->retry);
1099  sd.expire = htonl (soa->expire);
1100  sd.minimum = htonl (soa->minimum_ttl);
1101  GNUNET_memcpy (&dst[*off], &sd, sizeof(sd));
1102  (*off) += sizeof(sd);
1103  return GNUNET_OK;
1104 }
1105 
1106 
1119 int
1121  size_t dst_len,
1122  size_t *off,
1123  const struct GNUNET_DNSPARSER_SrvRecord *srv)
1124 {
1125  struct GNUNET_TUN_DnsSrvRecord sd;
1126  int ret;
1127 
1128  if (*off + sizeof(struct GNUNET_TUN_DnsSrvRecord) > dst_len)
1129  return GNUNET_NO;
1130  sd.prio = htons (srv->priority);
1131  sd.weight = htons (srv->weight);
1132  sd.port = htons (srv->port);
1133  GNUNET_memcpy (&dst[*off], &sd, sizeof(sd));
1134  (*off) += sizeof(sd);
1135  if (GNUNET_OK !=
1136  (ret =
1137  GNUNET_DNSPARSER_builder_add_name (dst, dst_len, off, srv->target)))
1138  return ret;
1139  return GNUNET_OK;
1140 }
1141 
1142 
1155 static int
1156 add_record (char *dst,
1157  size_t dst_len,
1158  size_t *off,
1159  const struct GNUNET_DNSPARSER_Record *record)
1160 {
1161  int ret;
1162  size_t start;
1163  size_t pos;
1164  struct GNUNET_TUN_DnsRecordLine rl;
1165 
1166  start = *off;
1168  dst_len
1169  - sizeof(
1170  struct GNUNET_TUN_DnsRecordLine),
1171  off,
1172  record->name);
1173  if (GNUNET_OK != ret)
1174  return ret;
1175  /* '*off' is now the position where we will need to write the record line */
1176 
1177  pos = *off + sizeof(struct GNUNET_TUN_DnsRecordLine);
1178  switch (record->type)
1179  {
1181  ret = GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &pos, record->data.mx);
1182  break;
1183 
1185  ret =
1186  GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &pos, record->data.cert);
1187  break;
1188 
1190  ret =
1191  GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &pos, record->data.soa);
1192  break;
1193 
1198  dst_len,
1199  &pos,
1200  record->data.hostname);
1201  break;
1202 
1204  ret =
1205  GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &pos, record->data.srv);
1206  break;
1207 
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 */
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:1156
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
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:99
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
static void record(void *cls, size_t data_size, const void *data)
Process recorded audio data.
char * idna_name
DNS IDNA name to lookup.
Definition: gnunet-gns.c:63
uint32_t data
The data value.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
static char buf[2048]
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
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
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:1032
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
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:854
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:966
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
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
#define GNUNET_DNSPARSER_TYPE_SRV
void GNUNET_DNSPARSER_free_record(struct GNUNET_DNSPARSER_Record *r)
Free the given DNS record.
Definition: dnsparser.c:169
#define GNUNET_DNSPARSER_TYPE_SOA
void GNUNET_DNSPARSER_free_cert(struct GNUNET_DNSPARSER_CertRecord *cert)
Free CERT information record.
Definition: dnsparser.c:124
#define GNUNET_DNSPARSER_TYPE_CERT
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
void GNUNET_DNSPARSER_free_srv(struct GNUNET_DNSPARSER_SrvRecord *srv)
Free SRV information record.
Definition: dnsparser.c:139
#define GNUNET_DNSPARSER_TYPE_PTR
struct GNUNET_DNSPARSER_Packet * GNUNET_DNSPARSER_parse(const char *udp_payload, size_t udp_payload_length)
Parse a UDP payload of a DNS packet in to a nice struct for further processing and manipulation.
Definition: dnsparser.c:656
int GNUNET_DNSPARSER_check_name(const char *name)
Check if a label in UTF-8 format can be coded into valid IDNA.
Definition: dnsparser.c:79
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
#define GNUNET_DNSPARSER_TYPE_NS
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:1079
#define GNUNET_DNSPARSER_TYPE_CNAME
#define GNUNET_DNSPARSER_TYPE_DNAME
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:1003
void GNUNET_DNSPARSER_free_soa(struct GNUNET_DNSPARSER_SoaRecord *soa)
Free SOA information record.
Definition: dnsparser.c:108
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:1120
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
void GNUNET_DNSPARSER_free_mx(struct GNUNET_DNSPARSER_MxRecord *mx)
Free MX information record.
Definition: dnsparser.c:154
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
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
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
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
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
#define GNUNET_DNSPARSER_TYPE_MX
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
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
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
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
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
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_TIME_UNIT_SECONDS
One second.
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:405
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:316
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:484
#define max(x, y)
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
const char * name
Information from CERT records (RFC 4034).
enum GNUNET_DNSPARSER_CertType cert_type
Certificate type.
char * certificate_data
Data of the certificate.
enum GNUNET_DNSPARSER_CertAlgorithm algorithm
Algorithm.
size_t certificate_size
Number of bytes in certificate_data.
uint16_t cert_tag
Certificate KeyTag.
Information from MX records (RFC 1035).
char * mxhost
Name of the mail server.
uint16_t preference
Preference for this entry (lower value is higher preference).
Easy-to-process, parsed version of a DNS packet.
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
char * name
Name of the record that the query is for (0-terminated).
void * data
Binary record data.
size_t data_len
Number of bytes in data.
A DNS response record.
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
struct GNUNET_DNSPARSER_SoaRecord * soa
SOA data for SOA records.
struct GNUNET_DNSPARSER_SrvRecord * srv
SRV data for SRV records.
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
char * hostname
For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
struct GNUNET_DNSPARSER_CertRecord * cert
CERT data for CERT records.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
struct GNUNET_TIME_Absolute expiration_time
When does the record expire?
union GNUNET_DNSPARSER_Record::@24 data
Payload of the record (which one of these is valid depends on the 'type').
char * name
Name of the record that the query is for (0-terminated).
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
Information from SOA records (RFC 1035).
uint32_t retry
Time interval that should elapse before a failed refresh should be retried.
char * mname
The domainname of the name server that was the original or primary source of data for this zone.
uint32_t refresh
Time interval before the zone should be refreshed.
uint32_t minimum_ttl
The bit minimum TTL field that should be exported with any RR from this zone.
char * rname
A domainname which specifies the mailbox of the person responsible for this zone.
uint32_t expire
Time value that specifies the upper limit on the time interval that can elapse before the zone is no ...
uint32_t serial
The version number of the original copy of the zone.
Information from SRV records (RFC 2782).
uint16_t port
TCP or UDP port of the service.
uint16_t weight
Relative weight for records with the same priority.
uint16_t priority
Preference for this entry (lower value is higher preference).
char * target
Hostname offering the service.
uint64_t rel_value_us
The actual value.
Payload of DNS CERT record.
uint16_t cert_type
Certificate type.
uint16_t cert_tag
Certificate KeyTag.
uint8_t algorithm
Algorithm.
unsigned int message_truncated
Set to 1 if message is truncated.
struct GNUNET_TUN_DnsFlags flags
Flags.
uint16_t query_count
Number of queries.
uint16_t authority_rcount
Number of authoritative answers.
uint16_t id
Unique identifier for the request/response.
uint16_t additional_rcount
Number of additional records.
uint16_t answer_rcount
Number of answers.
DNS query prefix.
uint16_t type
Desired type (GNUNET_DNSPARSER_TYPE_XXX).
uint16_t dns_traffic_class
Desired class (usually GNUNET_TUN_DNS_CLASS_INTERNET).
General DNS record prefix.
uint32_t ttl
Expiration for the record (in seconds).
uint16_t dns_traffic_class
Record class (usually GNUNET_TUN_DNS_CLASS_INTERNET).
uint16_t type
Record type (GNUNET_DNSPARSER_TYPE_XXX).
uint16_t data_len
Number of bytes of data that follow.
Payload of DNS SOA record (header).
uint32_t minimum
The bit minimum TTL field that should be exported with any RR from this zone.
uint32_t expire
Time value that specifies the upper limit on the time interval that can elapse before the zone is no ...
uint32_t refresh
Time interval before the zone should be refreshed.
uint32_t serial
The version number of the original copy of the zone.
uint32_t retry
Time interval that should elapse before a failed refresh should be retried.
Payload of DNS SRV record (header).
uint16_t prio
Preference for this entry (lower value is higher preference).
uint16_t weight
Relative weight for records with the same priority.
uint16_t port
TCP or UDP port of the service.