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 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.
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.
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/>.
20 * @file gnsrecord/plugin_gnsrecord_dns.c
21 * @brief gnsrecord plugin to provide the API for basic DNS records
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_dnsparser_lib.h"
27 #include "gnunet_gnsrecord_plugin.h"
31 * Convert the 'value' of a record to a string.
33 * @param cls closure, unused
34 * @param type type of the record
35 * @param data value in binary encoding
36 * @param data_size number of bytes in @a data
37 * @return NULL on error, otherwise human-readable representation of the value
40 dns_value_to_string (void *cls,
46 char tmp[INET6_ADDRSTRLEN];
50 case GNUNET_DNSPARSER_TYPE_A:
51 if (data_size != sizeof (struct in_addr))
53 if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
55 return GNUNET_strdup (tmp);
56 case GNUNET_DNSPARSER_TYPE_NS:
62 ns = GNUNET_DNSPARSER_parse_name (data,
69 GNUNET_free_non_null (ns);
74 case GNUNET_DNSPARSER_TYPE_CNAME:
80 cname = GNUNET_DNSPARSER_parse_name (data,
83 if ( (NULL == cname) ||
87 GNUNET_free_non_null (cname);
92 case GNUNET_DNSPARSER_TYPE_SOA:
94 struct GNUNET_DNSPARSER_SoaRecord *soa;
98 soa = GNUNET_DNSPARSER_parse_soa (data,
101 if ( (NULL == soa) ||
106 GNUNET_DNSPARSER_free_soa (soa);
109 GNUNET_asprintf (&result,
110 "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
118 GNUNET_DNSPARSER_free_soa (soa);
121 case GNUNET_DNSPARSER_TYPE_PTR:
127 ptr = GNUNET_DNSPARSER_parse_name (data,
130 if ( (NULL == ptr) ||
134 GNUNET_free_non_null (ptr);
139 case GNUNET_DNSPARSER_TYPE_CERT:
141 struct GNUNET_DNSPARSER_CertRecord *cert;
147 cert = GNUNET_DNSPARSER_parse_cert (data,
150 if ( (NULL == cert) ||
154 GNUNET_DNSPARSER_free_cert (cert);
157 len = GNUNET_STRINGS_base64_encode (cert->certificate_data,
158 cert->certificate_size,
160 GNUNET_asprintf (&result,
167 GNUNET_free (base64);
168 GNUNET_DNSPARSER_free_cert (cert);
171 case GNUNET_DNSPARSER_TYPE_MX:
173 struct GNUNET_DNSPARSER_MxRecord *mx;
177 mx = GNUNET_DNSPARSER_parse_mx (data,
184 GNUNET_DNSPARSER_free_mx (mx);
187 GNUNET_asprintf (&result,
189 (unsigned int) mx->preference,
191 GNUNET_DNSPARSER_free_mx (mx);
194 case GNUNET_DNSPARSER_TYPE_TXT:
195 return GNUNET_strndup (data, data_size);
196 case GNUNET_DNSPARSER_TYPE_AAAA:
197 if (data_size != sizeof (struct in6_addr))
199 if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
201 return GNUNET_strdup (tmp);
202 case GNUNET_DNSPARSER_TYPE_SRV:
204 struct GNUNET_DNSPARSER_SrvRecord *srv;
208 srv = GNUNET_DNSPARSER_parse_srv (data,
211 if ( (NULL == srv) ||
216 GNUNET_DNSPARSER_free_srv (srv);
219 GNUNET_asprintf (&result,
225 GNUNET_DNSPARSER_free_srv (srv);
228 case GNUNET_DNSPARSER_TYPE_TLSA:
230 const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
234 if (data_size < sizeof (struct GNUNET_TUN_DnsTlsaRecord))
235 return NULL; /* malformed */
237 hex = GNUNET_DNSPARSER_bin_to_hex (&tlsa[1],
238 data_size - sizeof (struct GNUNET_TUN_DnsTlsaRecord));
239 if (0 == GNUNET_asprintf (&tlsa_str,
241 (unsigned int) tlsa->usage,
242 (unsigned int) tlsa->selector,
243 (unsigned int) tlsa->matching_type,
247 GNUNET_free (tlsa_str);
260 * Convert RFC 4394 Mnemonics to the corresponding integer values.
262 * @param mnemonic string to look up
263 * @return the value, 0 if not found
266 rfc4398_mnemonic_to_value (const char *mnemonic)
269 const char *mnemonic;
286 for (i=0;NULL != table[i].mnemonic;i++)
287 if (0 == strcasecmp (mnemonic,
295 * Convert RFC 4034 algorithm types to the corresponding integer values.
297 * @param mnemonic string to look up
298 * @return the value, 0 if not found
301 rfc4034_mnemonic_to_value (const char *mnemonic)
304 const char *mnemonic;
313 { "PRIVATEDNS", 253 },
314 { "PRIVATEOID", 254 },
319 for (i=0;NULL != table[i].mnemonic;i++)
320 if (0 == strcasecmp (mnemonic,
328 * Convert human-readable version of a 'value' of a record to the binary
331 * @param cls closure, unused
332 * @param type type of the record
333 * @param s human-readable string
334 * @param data set to value in binary encoding (will be allocated)
335 * @param data_size set to number of bytes in @a data
336 * @return #GNUNET_OK on success
339 dns_string_to_value (void *cls,
345 struct in_addr value_a;
346 struct in6_addr value_aaaa;
347 struct GNUNET_TUN_DnsTlsaRecord *tlsa;
350 return GNUNET_SYSERR;
353 case GNUNET_DNSPARSER_TYPE_A:
354 if (1 != inet_pton (AF_INET, s, &value_a))
356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
357 _("Unable to parse IPv4 address `%s'\n"),
359 return GNUNET_SYSERR;
361 *data = GNUNET_new (struct in_addr);
362 GNUNET_memcpy (*data, &value_a, sizeof (value_a));
363 *data_size = sizeof (value_a);
365 case GNUNET_DNSPARSER_TYPE_NS:
372 GNUNET_DNSPARSER_builder_add_name (nsbuf,
377 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
378 _("Failed to serialize NS record with value `%s'\n"),
380 return GNUNET_SYSERR;
383 *data = GNUNET_malloc (off);
384 GNUNET_memcpy (*data, nsbuf, off);
387 case GNUNET_DNSPARSER_TYPE_CNAME:
394 GNUNET_DNSPARSER_builder_add_name (cnamebuf,
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
400 _("Failed to serialize CNAME record with value `%s'\n"),
402 return GNUNET_SYSERR;
405 *data = GNUNET_malloc (off);
406 GNUNET_memcpy (*data, cnamebuf, off);
409 case GNUNET_DNSPARSER_TYPE_CERT:
421 struct GNUNET_DNSPARSER_CertRecord cert;
423 sdup = GNUNET_strdup (s);
424 typep = strtok (sdup, " ");
425 if ( (NULL == typep) ||
426 ( (0 == (type = rfc4398_mnemonic_to_value (typep))) &&
427 ( (1 != SSCANF (typep,
430 (type > UINT16_MAX) ) ) )
433 return GNUNET_SYSERR;
435 keyp = strtok (NULL, " ");
436 if ( (NULL == keyp) ||
443 return GNUNET_SYSERR;
446 algp = strtok (NULL, " ");
447 if ( (NULL == algp) ||
448 ( (0 == (type = rfc4034_mnemonic_to_value (typep))) &&
449 ( (1 != sscanf (algp,
452 (alg > UINT8_MAX) ) ) )
455 return GNUNET_SYSERR;
457 certp = strtok (NULL, " ");
458 if ( (NULL == certp) ||
459 (0 == strlen (certp) ) )
462 return GNUNET_SYSERR;
464 cert_size = GNUNET_STRINGS_base64_decode (certp,
466 (void **) &cert_data);
468 cert.cert_type = type;
470 cert.algorithm = alg;
471 cert.certificate_size = cert_size;
472 cert.certificate_data = cert_data;
474 char certbuf[cert_size + sizeof (struct GNUNET_TUN_DnsCertRecord)];
479 GNUNET_DNSPARSER_builder_add_cert (certbuf,
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 _("Failed to serialize CERT record with %u bytes\n"),
486 (unsigned int) cert_size);
487 GNUNET_free (cert_data);
488 return GNUNET_SYSERR;
491 *data = GNUNET_malloc (off);
492 GNUNET_memcpy (*data, certbuf, off);
494 GNUNET_free (cert_data);
497 case GNUNET_DNSPARSER_TYPE_SOA:
499 struct GNUNET_DNSPARSER_SoaRecord soa;
501 char soa_rname[253 + 1];
502 char soa_mname[253 + 1];
503 unsigned int soa_serial;
504 unsigned int soa_refresh;
505 unsigned int soa_retry;
506 unsigned int soa_expire;
507 unsigned int soa_min;
511 "rname=%253s mname=%253s %u,%u,%u,%u,%u",
520 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
521 _("Unable to parse SOA record `%s'\n"),
523 return GNUNET_SYSERR;
525 soa.mname = soa_mname;
526 soa.rname = soa_rname;
527 soa.serial = (uint32_t) soa_serial;
528 soa.refresh =(uint32_t) soa_refresh;
529 soa.retry = (uint32_t) soa_retry;
530 soa.expire = (uint32_t) soa_expire;
531 soa.minimum_ttl = (uint32_t) soa_min;
534 GNUNET_DNSPARSER_builder_add_soa (soabuf,
539 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
540 _("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
543 return GNUNET_SYSERR;
546 *data = GNUNET_malloc (off);
547 GNUNET_memcpy (*data, soabuf, off);
550 case GNUNET_DNSPARSER_TYPE_PTR:
557 GNUNET_DNSPARSER_builder_add_name (ptrbuf,
562 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
563 _("Failed to serialize PTR record with value `%s'\n"),
565 return GNUNET_SYSERR;
568 *data = GNUNET_malloc (off);
569 GNUNET_memcpy (*data, ptrbuf, off);
572 case GNUNET_DNSPARSER_TYPE_MX:
574 struct GNUNET_DNSPARSER_MxRecord mx;
576 char mxhost[253 + 1];
577 unsigned int mx_pref;
585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586 _("Unable to parse MX record `%s'\n"),
588 return GNUNET_SYSERR;
590 mx.preference = (uint16_t) mx_pref;
595 GNUNET_DNSPARSER_builder_add_mx (mxbuf,
600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601 _("Failed to serialize MX record with hostname `%s'\n"),
603 return GNUNET_SYSERR;
606 *data = GNUNET_malloc (off);
607 GNUNET_memcpy (*data, mxbuf, off);
610 case GNUNET_DNSPARSER_TYPE_SRV:
612 struct GNUNET_DNSPARSER_SrvRecord srv;
614 char srvtarget[253 + 1];
615 unsigned int priority;
627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
628 _("Unable to parse SRV record `%s'\n"),
630 return GNUNET_SYSERR;
632 srv.priority = (uint16_t) priority;
633 srv.weight = (uint16_t) weight;
634 srv.port = (uint16_t) port;
635 srv.target = srvtarget;
638 GNUNET_DNSPARSER_builder_add_srv (srvbuf,
643 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
644 _("Failed to serialize SRV record with target `%s'\n"),
646 return GNUNET_SYSERR;
649 *data = GNUNET_malloc (off);
650 GNUNET_memcpy (*data, srvbuf, off);
653 case GNUNET_DNSPARSER_TYPE_TXT:
654 *data = GNUNET_strdup (s);
655 *data_size = strlen (s);
657 case GNUNET_DNSPARSER_TYPE_AAAA:
658 if (1 != inet_pton (AF_INET6, s, &value_aaaa))
660 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
661 _("Unable to parse IPv6 address `%s'\n"),
663 return GNUNET_SYSERR;
665 *data = GNUNET_new (struct in6_addr);
666 *data_size = sizeof (struct in6_addr);
667 GNUNET_memcpy (*data, &value_aaaa, sizeof (value_aaaa));
669 case GNUNET_DNSPARSER_TYPE_TLSA:
672 unsigned int selector;
673 unsigned int matching_type;
674 size_t slen = strlen (s) + 1;
684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
685 _("Unable to parse TLSA record string `%s'\n"),
688 return GNUNET_SYSERR;
691 *data_size = sizeof (struct GNUNET_TUN_DnsTlsaRecord) + strlen (hex) / 2;
692 *data = tlsa = GNUNET_malloc (*data_size);
693 tlsa->usage = (uint8_t) usage;
694 tlsa->selector = (uint8_t) selector;
695 tlsa->matching_type = (uint8_t) matching_type;
696 if (strlen (hex) / 2 !=
697 GNUNET_DNSPARSER_hex_to_bin (hex,
700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
701 _("Unable to parse TLSA record string `%s'\n"),
706 return GNUNET_SYSERR;
711 return GNUNET_SYSERR;
717 * Mapping of record type numbers to human-readable
724 { "A", GNUNET_DNSPARSER_TYPE_A },
725 { "NS", GNUNET_DNSPARSER_TYPE_NS },
726 { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
727 { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
728 { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
729 { "MX", GNUNET_DNSPARSER_TYPE_MX },
730 { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
731 { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
732 { "SRV", GNUNET_DNSPARSER_TYPE_SRV },
733 { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
734 { "CERT", GNUNET_DNSPARSER_TYPE_CERT },
740 * Convert a type name (i.e. "AAAA") to the corresponding number.
742 * @param cls closure, unused
743 * @param dns_typename name to convert
744 * @return corresponding number, UINT32_MAX on error
747 dns_typename_to_number (void *cls,
748 const char *dns_typename)
753 while ( (NULL != name_map[i].name) &&
754 (0 != strcasecmp (dns_typename, name_map[i].name)) )
756 return name_map[i].number;
761 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
763 * @param cls closure, unused
764 * @param type number of a type to convert
765 * @return corresponding typestring, NULL on error
768 dns_number_to_typename (void *cls,
774 while ( (NULL != name_map[i].name) &&
775 (type != name_map[i].number) )
777 return name_map[i].name;
782 * Entry point for the plugin.
785 * @return the exported block API
788 libgnunet_plugin_gnsrecord_dns_init (void *cls)
790 struct GNUNET_GNSRECORD_PluginFunctions *api;
792 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
793 api->value_to_string = &dns_value_to_string;
794 api->string_to_value = &dns_string_to_value;
795 api->typename_to_number = &dns_typename_to_number;
796 api->number_to_typename = &dns_number_to_typename;
802 * Exit point from the plugin.
804 * @param cls the return value from #libgnunet_plugin_block_test_init
808 libgnunet_plugin_gnsrecord_dns_done (void *cls)
810 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
816 /* end of plugin_gnsrecord_dns.c */