2 This file is part of GNUnet
3 Copyright (C) 2013, 2014 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file gnsrecord/plugin_gnsrecord_dns.c
23 * @brief gnsrecord plugin to provide the API for basic DNS records
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_dnsparser_lib.h"
29 #include "gnunet_gnsrecord_plugin.h"
33 * Convert the 'value' of a record to a string.
35 * @param cls closure, unused
36 * @param type type of the record
37 * @param data value in binary encoding
38 * @param data_size number of bytes in @a data
39 * @return NULL on error, otherwise human-readable representation of the value
42 dns_value_to_string (void *cls,
48 char tmp[INET6_ADDRSTRLEN];
52 case GNUNET_DNSPARSER_TYPE_A:
53 if (data_size != sizeof (struct in_addr))
55 if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
57 return GNUNET_strdup (tmp);
58 case GNUNET_DNSPARSER_TYPE_NS:
64 ns = GNUNET_DNSPARSER_parse_name (data,
71 GNUNET_free_non_null (ns);
76 case GNUNET_DNSPARSER_TYPE_CNAME:
82 cname = GNUNET_DNSPARSER_parse_name (data,
85 if ( (NULL == cname) ||
89 GNUNET_free_non_null (cname);
94 case GNUNET_DNSPARSER_TYPE_SOA:
96 struct GNUNET_DNSPARSER_SoaRecord *soa;
100 soa = GNUNET_DNSPARSER_parse_soa (data,
103 if ( (NULL == soa) ||
108 GNUNET_DNSPARSER_free_soa (soa);
111 GNUNET_asprintf (&result,
112 "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
120 GNUNET_DNSPARSER_free_soa (soa);
123 case GNUNET_DNSPARSER_TYPE_PTR:
129 ptr = GNUNET_DNSPARSER_parse_name (data,
132 if ( (NULL == ptr) ||
136 GNUNET_free_non_null (ptr);
141 case GNUNET_DNSPARSER_TYPE_CERT:
143 struct GNUNET_DNSPARSER_CertRecord *cert;
149 cert = GNUNET_DNSPARSER_parse_cert (data,
152 if ( (NULL == cert) ||
156 GNUNET_DNSPARSER_free_cert (cert);
159 len = GNUNET_STRINGS_base64_encode (cert->certificate_data,
160 cert->certificate_size,
162 GNUNET_asprintf (&result,
169 GNUNET_free (base64);
170 GNUNET_DNSPARSER_free_cert (cert);
173 case GNUNET_DNSPARSER_TYPE_MX:
175 struct GNUNET_DNSPARSER_MxRecord *mx;
179 mx = GNUNET_DNSPARSER_parse_mx (data,
186 GNUNET_DNSPARSER_free_mx (mx);
189 GNUNET_asprintf (&result,
191 (unsigned int) mx->preference,
193 GNUNET_DNSPARSER_free_mx (mx);
196 case GNUNET_DNSPARSER_TYPE_TXT:
197 return GNUNET_strndup (data, data_size);
198 case GNUNET_DNSPARSER_TYPE_AAAA:
199 if (data_size != sizeof (struct in6_addr))
201 if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
203 return GNUNET_strdup (tmp);
204 case GNUNET_DNSPARSER_TYPE_SRV:
206 struct GNUNET_DNSPARSER_SrvRecord *srv;
210 srv = GNUNET_DNSPARSER_parse_srv (data,
213 if ( (NULL == srv) ||
218 GNUNET_DNSPARSER_free_srv (srv);
221 GNUNET_asprintf (&result,
227 GNUNET_DNSPARSER_free_srv (srv);
230 case GNUNET_DNSPARSER_TYPE_TLSA:
232 const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
236 if (data_size < sizeof (struct GNUNET_TUN_DnsTlsaRecord))
237 return NULL; /* malformed */
239 hex = GNUNET_DNSPARSER_bin_to_hex (&tlsa[1],
240 data_size - sizeof (struct GNUNET_TUN_DnsTlsaRecord));
241 if (0 == GNUNET_asprintf (&tlsa_str,
243 (unsigned int) tlsa->usage,
244 (unsigned int) tlsa->selector,
245 (unsigned int) tlsa->matching_type,
249 GNUNET_free (tlsa_str);
262 * Convert RFC 4394 Mnemonics to the corresponding integer values.
264 * @param mnemonic string to look up
265 * @return the value, 0 if not found
268 rfc4398_mnemonic_to_value (const char *mnemonic)
271 const char *mnemonic;
288 for (i=0;NULL != table[i].mnemonic;i++)
289 if (0 == strcasecmp (mnemonic,
297 * Convert RFC 4034 algorithm types to the corresponding integer values.
299 * @param mnemonic string to look up
300 * @return the value, 0 if not found
303 rfc4034_mnemonic_to_value (const char *mnemonic)
306 const char *mnemonic;
315 { "PRIVATEDNS", 253 },
316 { "PRIVATEOID", 254 },
321 for (i=0;NULL != table[i].mnemonic;i++)
322 if (0 == strcasecmp (mnemonic,
330 * Convert human-readable version of a 'value' of a record to the binary
333 * @param cls closure, unused
334 * @param type type of the record
335 * @param s human-readable string
336 * @param data set to value in binary encoding (will be allocated)
337 * @param data_size set to number of bytes in @a data
338 * @return #GNUNET_OK on success
341 dns_string_to_value (void *cls,
347 struct in_addr value_a;
348 struct in6_addr value_aaaa;
349 struct GNUNET_TUN_DnsTlsaRecord *tlsa;
352 return GNUNET_SYSERR;
355 case GNUNET_DNSPARSER_TYPE_A:
356 if (1 != inet_pton (AF_INET, s, &value_a))
358 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359 _("Unable to parse IPv4 address `%s'\n"),
361 return GNUNET_SYSERR;
363 *data = GNUNET_new (struct in_addr);
364 GNUNET_memcpy (*data, &value_a, sizeof (value_a));
365 *data_size = sizeof (value_a);
367 case GNUNET_DNSPARSER_TYPE_NS:
374 GNUNET_DNSPARSER_builder_add_name (nsbuf,
379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
380 _("Failed to serialize NS record with value `%s'\n"),
382 return GNUNET_SYSERR;
385 *data = GNUNET_malloc (off);
386 GNUNET_memcpy (*data, nsbuf, off);
389 case GNUNET_DNSPARSER_TYPE_CNAME:
396 GNUNET_DNSPARSER_builder_add_name (cnamebuf,
401 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
402 _("Failed to serialize CNAME record with value `%s'\n"),
404 return GNUNET_SYSERR;
407 *data = GNUNET_malloc (off);
408 GNUNET_memcpy (*data, cnamebuf, off);
411 case GNUNET_DNSPARSER_TYPE_CERT:
423 struct GNUNET_DNSPARSER_CertRecord cert;
425 sdup = GNUNET_strdup (s);
426 typep = strtok (sdup, " ");
427 if ( (NULL == typep) ||
428 ( (0 == (type = rfc4398_mnemonic_to_value (typep))) &&
429 ( (1 != SSCANF (typep,
432 (type > UINT16_MAX) ) ) )
435 return GNUNET_SYSERR;
437 keyp = strtok (NULL, " ");
438 if ( (NULL == keyp) ||
445 return GNUNET_SYSERR;
448 algp = strtok (NULL, " ");
449 if ( (NULL == algp) ||
450 ( (0 == (type = rfc4034_mnemonic_to_value (typep))) &&
451 ( (1 != sscanf (algp,
454 (alg > UINT8_MAX) ) ) )
457 return GNUNET_SYSERR;
459 certp = strtok (NULL, " ");
460 if ( (NULL == certp) ||
461 (0 == strlen (certp) ) )
464 return GNUNET_SYSERR;
466 cert_size = GNUNET_STRINGS_base64_decode (certp,
470 cert.cert_type = type;
472 cert.algorithm = alg;
473 cert.certificate_size = cert_size;
474 cert.certificate_data = cert_data;
476 char certbuf[cert_size + sizeof (struct GNUNET_TUN_DnsCertRecord)];
481 GNUNET_DNSPARSER_builder_add_cert (certbuf,
486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
487 _("Failed to serialize CERT record with %u bytes\n"),
488 (unsigned int) cert_size);
489 GNUNET_free (cert_data);
490 return GNUNET_SYSERR;
493 *data = GNUNET_malloc (off);
494 GNUNET_memcpy (*data, certbuf, off);
496 GNUNET_free (cert_data);
499 case GNUNET_DNSPARSER_TYPE_SOA:
501 struct GNUNET_DNSPARSER_SoaRecord soa;
503 char soa_rname[253 + 1];
504 char soa_mname[253 + 1];
505 unsigned int soa_serial;
506 unsigned int soa_refresh;
507 unsigned int soa_retry;
508 unsigned int soa_expire;
509 unsigned int soa_min;
513 "rname=%253s mname=%253s %u,%u,%u,%u,%u",
522 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
523 _("Unable to parse SOA record `%s'\n"),
525 return GNUNET_SYSERR;
527 soa.mname = soa_mname;
528 soa.rname = soa_rname;
529 soa.serial = (uint32_t) soa_serial;
530 soa.refresh =(uint32_t) soa_refresh;
531 soa.retry = (uint32_t) soa_retry;
532 soa.expire = (uint32_t) soa_expire;
533 soa.minimum_ttl = (uint32_t) soa_min;
536 GNUNET_DNSPARSER_builder_add_soa (soabuf,
541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
542 _("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
545 return GNUNET_SYSERR;
548 *data = GNUNET_malloc (off);
549 GNUNET_memcpy (*data, soabuf, off);
552 case GNUNET_DNSPARSER_TYPE_PTR:
559 GNUNET_DNSPARSER_builder_add_name (ptrbuf,
564 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
565 _("Failed to serialize PTR record with value `%s'\n"),
567 return GNUNET_SYSERR;
570 *data = GNUNET_malloc (off);
571 GNUNET_memcpy (*data, ptrbuf, off);
574 case GNUNET_DNSPARSER_TYPE_MX:
576 struct GNUNET_DNSPARSER_MxRecord mx;
578 char mxhost[253 + 1];
579 unsigned int mx_pref;
587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
588 _("Unable to parse MX record `%s'\n"),
590 return GNUNET_SYSERR;
592 mx.preference = (uint16_t) mx_pref;
597 GNUNET_DNSPARSER_builder_add_mx (mxbuf,
602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603 _("Failed to serialize MX record with hostname `%s'\n"),
605 return GNUNET_SYSERR;
608 *data = GNUNET_malloc (off);
609 GNUNET_memcpy (*data, mxbuf, off);
612 case GNUNET_DNSPARSER_TYPE_SRV:
614 struct GNUNET_DNSPARSER_SrvRecord srv;
616 char srvtarget[253 + 1];
617 unsigned int priority;
629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630 _("Unable to parse SRV record `%s'\n"),
632 return GNUNET_SYSERR;
634 srv.priority = (uint16_t) priority;
635 srv.weight = (uint16_t) weight;
636 srv.port = (uint16_t) port;
637 srv.target = srvtarget;
640 GNUNET_DNSPARSER_builder_add_srv (srvbuf,
645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
646 _("Failed to serialize SRV record with target `%s'\n"),
648 return GNUNET_SYSERR;
651 *data = GNUNET_malloc (off);
652 GNUNET_memcpy (*data, srvbuf, off);
655 case GNUNET_DNSPARSER_TYPE_TXT:
656 *data = GNUNET_strdup (s);
657 *data_size = strlen (s);
659 case GNUNET_DNSPARSER_TYPE_AAAA:
660 if (1 != inet_pton (AF_INET6, s, &value_aaaa))
662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663 _("Unable to parse IPv6 address `%s'\n"),
665 return GNUNET_SYSERR;
667 *data = GNUNET_new (struct in6_addr);
668 *data_size = sizeof (struct in6_addr);
669 GNUNET_memcpy (*data, &value_aaaa, sizeof (value_aaaa));
671 case GNUNET_DNSPARSER_TYPE_TLSA:
674 unsigned int selector;
675 unsigned int matching_type;
676 size_t slen = strlen (s) + 1;
686 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
687 _("Unable to parse TLSA record string `%s'\n"),
690 return GNUNET_SYSERR;
693 *data_size = sizeof (struct GNUNET_TUN_DnsTlsaRecord) + strlen (hex) / 2;
694 *data = tlsa = GNUNET_malloc (*data_size);
695 tlsa->usage = (uint8_t) usage;
696 tlsa->selector = (uint8_t) selector;
697 tlsa->matching_type = (uint8_t) matching_type;
698 if (strlen (hex) / 2 !=
699 GNUNET_DNSPARSER_hex_to_bin (hex,
702 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703 _("Unable to parse TLSA record string `%s'\n"),
708 return GNUNET_SYSERR;
713 return GNUNET_SYSERR;
719 * Mapping of record type numbers to human-readable
726 { "A", GNUNET_DNSPARSER_TYPE_A },
727 { "NS", GNUNET_DNSPARSER_TYPE_NS },
728 { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
729 { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
730 { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
731 { "MX", GNUNET_DNSPARSER_TYPE_MX },
732 { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
733 { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
734 { "SRV", GNUNET_DNSPARSER_TYPE_SRV },
735 { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
736 { "CERT", GNUNET_DNSPARSER_TYPE_CERT },
742 * Convert a type name (i.e. "AAAA") to the corresponding number.
744 * @param cls closure, unused
745 * @param dns_typename name to convert
746 * @return corresponding number, UINT32_MAX on error
749 dns_typename_to_number (void *cls,
750 const char *dns_typename)
755 while ( (NULL != name_map[i].name) &&
756 (0 != strcasecmp (dns_typename, name_map[i].name)) )
758 return name_map[i].number;
763 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
765 * @param cls closure, unused
766 * @param type number of a type to convert
767 * @return corresponding typestring, NULL on error
770 dns_number_to_typename (void *cls,
776 while ( (NULL != name_map[i].name) &&
777 (type != name_map[i].number) )
779 return name_map[i].name;
784 * Entry point for the plugin.
787 * @return the exported block API
790 libgnunet_plugin_gnsrecord_dns_init (void *cls)
792 struct GNUNET_GNSRECORD_PluginFunctions *api;
794 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
795 api->value_to_string = &dns_value_to_string;
796 api->string_to_value = &dns_string_to_value;
797 api->typename_to_number = &dns_typename_to_number;
798 api->number_to_typename = &dns_number_to_typename;
804 * Exit point from the plugin.
806 * @param cls the return value from #libgnunet_plugin_block_test_init
810 libgnunet_plugin_gnsrecord_dns_done (void *cls)
812 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
818 /* end of plugin_gnsrecord_dns.c */