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 #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;
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);
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);
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);
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: {
773  }
774  }
775  return dup;
776 }
777 
778 
787  const struct GNUNET_DNSPARSER_SoaRecord *r)
788 {
789  struct GNUNET_DNSPARSER_SoaRecord *dup = GNUNET_memdup(r, sizeof(*r));
790 
791  dup->mname = GNUNET_strdup(r->mname);
792  dup->rname = GNUNET_strdup(r->rname);
793  return dup;
794 }
795 
796 
805  const struct GNUNET_DNSPARSER_CertRecord *r)
806 {
807  struct GNUNET_DNSPARSER_CertRecord *dup = GNUNET_memdup(r, sizeof(*r));
808 
810  return dup;
811 }
812 
813 
822 {
823  struct GNUNET_DNSPARSER_MxRecord *dup = GNUNET_memdup(r, sizeof(*r));
824 
825  dup->mxhost = GNUNET_strdup(r->mxhost);
826  return dup;
827 }
828 
829 
838  const struct GNUNET_DNSPARSER_SrvRecord *r)
839 {
840  struct GNUNET_DNSPARSER_SrvRecord *dup = GNUNET_memdup(r, sizeof(*r));
841 
842  dup->target = GNUNET_strdup(r->target);
843  return dup;
844 }
845 
846 
852 void
854 {
855  for (unsigned int i = 0; i < p->num_queries; i++)
858  for (unsigned int i = 0; i < p->num_answers; i++)
861  for (unsigned int i = 0; i < p->num_authority_records; i++)
864  for (unsigned int i = 0; i < p->num_additional_records; i++)
867  GNUNET_free(p);
868 }
869 
870 
871 /* ********************** DNS packet assembly code **************** */
872 
873 
887 int
889  size_t dst_len,
890  size_t *off,
891  const char *name)
892 {
893  const char *dot;
894  const char *idna_name;
895  char *idna_start;
896  size_t start;
897  size_t pos;
898  size_t len;
899  Idna_rc rc;
900 
901  if (NULL == name)
902  return GNUNET_SYSERR;
903 
904  if (IDNA_SUCCESS !=
905  (rc = idna_to_ascii_8z(name, &idna_start, IDNA_ALLOW_UNASSIGNED)))
906  {
908  _(
909  "Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"),
910  name,
911  idna_strerror(rc));
912  return GNUNET_NO;
913  }
914  idna_name = idna_start;
915  start = *off;
916  if (start + strlen(idna_name) + 2 > dst_len)
917  goto fail;
918  pos = start;
919  do
920  {
921  dot = strchr(idna_name, '.');
922  if (NULL == dot)
923  len = strlen(idna_name);
924  else
925  len = dot - idna_name;
926  if ((len >= 64) || (0 == len))
927  {
929  "Invalid DNS name `%s': label with %u characters encountered\n",
930  name,
931  (unsigned int)len);
932  goto fail; /* label too long or empty */
933  }
934  dst[pos++] = (char)(uint8_t)len;
935  GNUNET_memcpy(&dst[pos], idna_name, len);
936  pos += len;
937  idna_name += len + 1; /* also skip dot */
938  }
939  while (NULL != dot);
940  dst[pos++] = '\0'; /* terminator */
941  *off = pos;
942  free(idna_start);
943  return GNUNET_OK;
944 fail:
945  free(idna_start);
946  return GNUNET_NO;
947 }
948 
949 
962 int
964  size_t dst_len,
965  size_t *off,
966  const struct GNUNET_DNSPARSER_Query *query)
967 {
968  int ret;
969  struct GNUNET_TUN_DnsQueryLine ql;
970 
972  dst_len -
973  sizeof(
974  struct GNUNET_TUN_DnsQueryLine),
975  off,
976  query->name);
977  if (ret != GNUNET_OK)
978  return ret;
979  ql.type = htons(query->type);
980  ql.dns_traffic_class = htons(query->dns_traffic_class);
981  GNUNET_memcpy(&dst[*off], &ql, sizeof(ql));
982  (*off) += sizeof(ql);
983  return GNUNET_OK;
984 }
985 
986 
999 int
1001  size_t dst_len,
1002  size_t *off,
1003  const struct GNUNET_DNSPARSER_MxRecord *mx)
1004 {
1005  uint16_t mxpref;
1006 
1007  if (*off + sizeof(uint16_t) > dst_len)
1008  return GNUNET_NO;
1009  mxpref = htons(mx->preference);
1010  GNUNET_memcpy(&dst[*off], &mxpref, sizeof(mxpref));
1011  (*off) += sizeof(mxpref);
1012  return GNUNET_DNSPARSER_builder_add_name(dst, dst_len, off, mx->mxhost);
1013 }
1014 
1015 
1028 int
1030  char *dst,
1031  size_t dst_len,
1032  size_t *off,
1033  const struct GNUNET_DNSPARSER_CertRecord *cert)
1034 {
1035  struct GNUNET_TUN_DnsCertRecord dcert;
1036 
1037 #ifdef __clang__
1038 #pragma clang diagnostic push
1039 #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
1040 #endif
1041  if ((cert->cert_type > UINT16_MAX) || (cert->algorithm > UINT8_MAX))
1042  {
1043  GNUNET_break(0);
1044  return GNUNET_SYSERR;
1045  }
1046 #ifdef __clang__
1047 #pragma clang diagnostic pop
1048 #endif
1049  if (*off + sizeof(struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size >
1050  dst_len)
1051  return GNUNET_NO;
1052  dcert.cert_type = htons((uint16_t)cert->cert_type);
1053  dcert.cert_tag = htons((uint16_t)cert->cert_tag);
1054  dcert.algorithm = (uint8_t)cert->algorithm;
1055  GNUNET_memcpy(&dst[*off], &dcert, sizeof(dcert));
1056  (*off) += sizeof(dcert);
1057  GNUNET_memcpy(&dst[*off], cert->certificate_data, cert->certificate_size);
1058  (*off) += cert->certificate_size;
1059  return GNUNET_OK;
1060 }
1061 
1062 
1075 int
1077  size_t dst_len,
1078  size_t *off,
1079  const struct GNUNET_DNSPARSER_SoaRecord *soa)
1080 {
1081  struct GNUNET_TUN_DnsSoaRecord sd;
1082  int ret;
1083 
1084  if ((GNUNET_OK !=
1085  (ret =
1086  GNUNET_DNSPARSER_builder_add_name(dst, dst_len, off, soa->mname))) ||
1087  (GNUNET_OK !=
1088  (ret =
1089  GNUNET_DNSPARSER_builder_add_name(dst, dst_len, off, soa->rname))))
1090  return ret;
1091  if (*off + sizeof(struct GNUNET_TUN_DnsSoaRecord) > dst_len)
1092  return GNUNET_NO;
1093  sd.serial = htonl(soa->serial);
1094  sd.refresh = htonl(soa->refresh);
1095  sd.retry = htonl(soa->retry);
1096  sd.expire = htonl(soa->expire);
1097  sd.minimum = htonl(soa->minimum_ttl);
1098  GNUNET_memcpy(&dst[*off], &sd, sizeof(sd));
1099  (*off) += sizeof(sd);
1100  return GNUNET_OK;
1101 }
1102 
1103 
1116 int
1118  size_t dst_len,
1119  size_t *off,
1120  const struct GNUNET_DNSPARSER_SrvRecord *srv)
1121 {
1122  struct GNUNET_TUN_DnsSrvRecord sd;
1123  int ret;
1124 
1125  if (*off + sizeof(struct GNUNET_TUN_DnsSrvRecord) > dst_len)
1126  return GNUNET_NO;
1127  sd.prio = htons(srv->priority);
1128  sd.weight = htons(srv->weight);
1129  sd.port = htons(srv->port);
1130  GNUNET_memcpy(&dst[*off], &sd, sizeof(sd));
1131  (*off) += sizeof(sd);
1132  if (GNUNET_OK !=
1133  (ret =
1134  GNUNET_DNSPARSER_builder_add_name(dst, dst_len, off, srv->target)))
1135  return ret;
1136  return GNUNET_OK;
1137 }
1138 
1139 
1152 static int
1153 add_record(char *dst,
1154  size_t dst_len,
1155  size_t *off,
1156  const struct GNUNET_DNSPARSER_Record *record)
1157 {
1158  int ret;
1159  size_t start;
1160  size_t pos;
1161  struct GNUNET_TUN_DnsRecordLine rl;
1162 
1163  start = *off;
1165  dst_len -
1166  sizeof(
1167  struct GNUNET_TUN_DnsRecordLine),
1168  off,
1169  record->name);
1170  if (GNUNET_OK != ret)
1171  return ret;
1172  /* '*off' is now the position where we will need to write the record line */
1173 
1174  pos = *off + sizeof(struct GNUNET_TUN_DnsRecordLine);
1175  switch (record->type)
1176  {
1178  ret = GNUNET_DNSPARSER_builder_add_mx(dst, dst_len, &pos, record->data.mx);
1179  break;
1180 
1182  ret =
1183  GNUNET_DNSPARSER_builder_add_cert(dst, dst_len, &pos, record->data.cert);
1184  break;
1185 
1187  ret =
1188  GNUNET_DNSPARSER_builder_add_soa(dst, dst_len, &pos, record->data.soa);
1189  break;
1190 
1195  dst_len,
1196  &pos,
1197  record->data.hostname);
1198  break;
1199 
1201  ret =
1202  GNUNET_DNSPARSER_builder_add_srv(dst, dst_len, &pos, record->data.srv);
1203  break;
1204 
1205  default:
1206  if (pos + record->data.raw.data_len > dst_len)
1207  {
1208  ret = GNUNET_NO;
1209  break;
1210  }
1211  GNUNET_memcpy(&dst[pos], record->data.raw.data, record->data.raw.data_len);
1212  pos += record->data.raw.data_len;
1213  ret = GNUNET_OK;
1214  break;
1215  }
1216  if (GNUNET_OK != ret)
1217  {
1218  *off = start;
1219  return GNUNET_NO;
1220  }
1221 
1222  if (pos - (*off + sizeof(struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX)
1223  {
1224  /* record data too long */
1225  *off = start;
1226  return GNUNET_NO;
1227  }
1228  rl.type = htons(record->type);
1229  rl.dns_traffic_class = htons(record->dns_traffic_class);
1230  rl.ttl = htonl(
1232  1000LL / 1000LL); /* in seconds */
1233  rl.data_len = htons(
1234  (uint16_t)(pos - (*off + sizeof(struct GNUNET_TUN_DnsRecordLine))));
1235  GNUNET_memcpy(&dst[*off], &rl, sizeof(struct GNUNET_TUN_DnsRecordLine));
1236  *off = pos;
1237  return GNUNET_OK;
1238 }
1239 
1240 
1255 int
1257  uint16_t max,
1258  char **buf,
1259  size_t *buf_length)
1260 {
1261  struct GNUNET_TUN_DnsHeader dns;
1262  size_t off;
1263  char tmp[max];
1264  int ret;
1265  int trc;
1266 
1267  if ((p->num_queries > UINT16_MAX) || (p->num_answers > UINT16_MAX) ||
1268  (p->num_authority_records > UINT16_MAX) ||
1269  (p->num_additional_records > UINT16_MAX))
1270  return GNUNET_SYSERR;
1271  dns.id = p->id;
1272  dns.flags = p->flags;
1273  dns.query_count = htons(p->num_queries);
1274  dns.answer_rcount = htons(p->num_answers);
1275  dns.authority_rcount = htons(p->num_authority_records);
1276  dns.additional_rcount = htons(p->num_additional_records);
1277 
1278  off = sizeof(struct GNUNET_TUN_DnsHeader);
1279  trc = GNUNET_NO;
1280  for (unsigned int i = 0; i < p->num_queries; i++)
1281  {
1283  sizeof(tmp),
1284  &off,
1285  &p->queries[i]);
1286  if (GNUNET_SYSERR == ret)
1287  return GNUNET_SYSERR;
1288  if (GNUNET_NO == ret)
1289  {
1290  dns.query_count = htons((uint16_t)(i - 1));
1291  trc = GNUNET_YES;
1292  break;
1293  }
1294  }
1295  for (unsigned int i = 0; i < p->num_answers; i++)
1296  {
1297  ret = add_record(tmp, sizeof(tmp), &off, &p->answers[i]);
1298  if (GNUNET_SYSERR == ret)
1299  return GNUNET_SYSERR;
1300  if (GNUNET_NO == ret)
1301  {
1302  dns.answer_rcount = htons((uint16_t)(i - 1));
1303  trc = GNUNET_YES;
1304  break;
1305  }
1306  }
1307  for (unsigned int i = 0; i < p->num_authority_records; i++)
1308  {
1309  ret = add_record(tmp, sizeof(tmp), &off, &p->authority_records[i]);
1310  if (GNUNET_SYSERR == ret)
1311  return GNUNET_SYSERR;
1312  if (GNUNET_NO == ret)
1313  {
1314  dns.authority_rcount = htons((uint16_t)(i - 1));
1315  trc = GNUNET_YES;
1316  break;
1317  }
1318  }
1319  for (unsigned int i = 0; i < p->num_additional_records; i++)
1320  {
1321  ret = add_record(tmp, sizeof(tmp), &off, &p->additional_records[i]);
1322  if (GNUNET_SYSERR == ret)
1323  return GNUNET_SYSERR;
1324  if (GNUNET_NO == ret)
1325  {
1326  dns.additional_rcount = htons(i - 1);
1327  trc = GNUNET_YES;
1328  break;
1329  }
1330  }
1331 
1332  if (GNUNET_YES == trc)
1333  dns.flags.message_truncated = 1;
1334  GNUNET_memcpy(tmp, &dns, sizeof(struct GNUNET_TUN_DnsHeader));
1335 
1336  *buf = GNUNET_malloc(off);
1337  *buf_length = off;
1338  GNUNET_memcpy(*buf, tmp, off);
1339  if (GNUNET_YES == trc)
1340  return GNUNET_NO;
1341  return GNUNET_OK;
1342 }
1343 
1344 
1352 char *
1354 {
1355  char *ret;
1356  size_t off;
1357  const uint8_t *idata;
1358 
1359  idata = data;
1360  ret = GNUNET_malloc(data_size * 2 + 1);
1361  for (off = 0; off < data_size; off++)
1362  sprintf(&ret[off * 2], "%02x", idata[off]);
1363  return ret;
1364 }
1365 
1366 
1375 size_t
1376 GNUNET_DNSPARSER_hex_to_bin(const char *hex, void *data)
1377 {
1378  size_t data_size;
1379  size_t off;
1380  uint8_t *idata;
1381  unsigned int h;
1382  char in[3];
1383 
1384  data_size = strlen(hex) / 2;
1385  idata = data;
1386  in[2] = '\0';
1387  for (off = 0; off < data_size; off++)
1388  {
1389  in[0] = tolower((unsigned char)hex[off * 2]);
1390  in[1] = tolower((unsigned char)hex[off * 2 + 1]);
1391  if (1 != sscanf(in, "%x", &h))
1392  return off;
1393  idata[off] = (uint8_t)h;
1394  }
1395  return off;
1396 }
1397 
1398 
1399 /* 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:1153
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
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:1256
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:1117
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:786
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:853
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:804
#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...
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: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:1376
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:837
#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.
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:440
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:1076
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:821
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:1029
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:1000
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: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
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:963
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).
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:888
#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: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:1353
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...