636a734030f2ad1f94cbcdd50c2b54cb947c3a2c
[oweals/gnunet.git] / src / gnsrecord / plugin_gnsrecord_dns.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2013, 2014 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
21 /**
22  * @file gnsrecord/plugin_gnsrecord_dns.c
23  * @brief gnsrecord plugin to provide the API for basic DNS records
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_dnsparser_lib.h"
29 #include "gnunet_gnsrecord_plugin.h"
30
31
32 /**
33  * Convert the 'value' of a record to a string.
34  *
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
40  */
41 static char *
42 dns_value_to_string (void *cls,
43                      uint32_t type,
44                      const void *data,
45                      size_t data_size)
46 {
47   char *result;
48   char tmp[INET6_ADDRSTRLEN];
49
50   switch (type)
51   {
52   case GNUNET_DNSPARSER_TYPE_A:
53     if (data_size != sizeof (struct in_addr))
54       return NULL;
55     if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
56       return NULL;
57     return GNUNET_strdup (tmp);
58   case GNUNET_DNSPARSER_TYPE_NS: {
59     char *ns;
60     size_t off;
61
62     off = 0;
63     ns = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
64     if ((NULL == ns) || (off != data_size))
65     {
66       GNUNET_break_op (0);
67       GNUNET_free_non_null (ns);
68       return NULL;
69     }
70     return ns;
71   }
72   case GNUNET_DNSPARSER_TYPE_CNAME: {
73     char *cname;
74     size_t off;
75
76     off = 0;
77     cname = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
78     if ((NULL == cname) || (off != data_size))
79     {
80       GNUNET_break_op (0);
81       GNUNET_free_non_null (cname);
82       return NULL;
83     }
84     return cname;
85   }
86   case GNUNET_DNSPARSER_TYPE_SOA: {
87     struct GNUNET_DNSPARSER_SoaRecord *soa;
88     size_t off;
89
90     off = 0;
91     soa = GNUNET_DNSPARSER_parse_soa (data, data_size, &off);
92     if ((NULL == soa) || (off != data_size))
93     {
94       GNUNET_break_op (0);
95       if (NULL != soa)
96         GNUNET_DNSPARSER_free_soa (soa);
97       return NULL;
98     }
99     GNUNET_asprintf (&result,
100                      "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
101                      soa->rname,
102                      soa->mname,
103                      soa->serial,
104                      soa->refresh,
105                      soa->retry,
106                      soa->expire,
107                      soa->minimum_ttl);
108     GNUNET_DNSPARSER_free_soa (soa);
109     return result;
110   }
111   case GNUNET_DNSPARSER_TYPE_PTR: {
112     char *ptr;
113     size_t off;
114
115     off = 0;
116     ptr = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
117     if ((NULL == ptr) || (off != data_size))
118     {
119       GNUNET_break_op (0);
120       GNUNET_free_non_null (ptr);
121       return NULL;
122     }
123     return ptr;
124   }
125   case GNUNET_DNSPARSER_TYPE_CERT: {
126     struct GNUNET_DNSPARSER_CertRecord *cert;
127     size_t off;
128     char *base64;
129     int len;
130
131     off = 0;
132     cert = GNUNET_DNSPARSER_parse_cert (data, data_size, &off);
133     if ((NULL == cert) || (off != data_size))
134     {
135       GNUNET_break_op (0);
136       GNUNET_DNSPARSER_free_cert (cert);
137       return NULL;
138     }
139     len = GNUNET_STRINGS_base64_encode (cert->certificate_data,
140                                         cert->certificate_size,
141                                         &base64);
142     GNUNET_asprintf (&result,
143                      "%u %u %u %.*s",
144                      cert->cert_type,
145                      cert->cert_tag,
146                      cert->algorithm,
147                      len,
148                      base64);
149     GNUNET_free (base64);
150     GNUNET_DNSPARSER_free_cert (cert);
151     return result;
152   }
153   case GNUNET_DNSPARSER_TYPE_MX: {
154     struct GNUNET_DNSPARSER_MxRecord *mx;
155     size_t off;
156
157     off = 0;
158     mx = GNUNET_DNSPARSER_parse_mx (data, data_size, &off);
159     if ((NULL == mx) || (off != data_size))
160     {
161       GNUNET_break_op (0);
162       GNUNET_DNSPARSER_free_mx (mx);
163       return NULL;
164     }
165     GNUNET_asprintf (&result,
166                      "%u,%s",
167                      (unsigned int) mx->preference,
168                      mx->mxhost);
169     GNUNET_DNSPARSER_free_mx (mx);
170     return result;
171   }
172   case GNUNET_DNSPARSER_TYPE_TXT:
173     return GNUNET_strndup (data, data_size);
174   case GNUNET_DNSPARSER_TYPE_AAAA:
175     if (data_size != sizeof (struct in6_addr))
176       return NULL;
177     if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
178       return NULL;
179     return GNUNET_strdup (tmp);
180   case GNUNET_DNSPARSER_TYPE_SRV: {
181     struct GNUNET_DNSPARSER_SrvRecord *srv;
182     size_t off;
183
184     off = 0;
185     srv = GNUNET_DNSPARSER_parse_srv (data, data_size, &off);
186     if ((NULL == srv) || (off != data_size))
187     {
188       GNUNET_break_op (0);
189       if (NULL != srv)
190         GNUNET_DNSPARSER_free_srv (srv);
191       return NULL;
192     }
193     GNUNET_asprintf (&result,
194                      "%d %d %d %s",
195                      srv->priority,
196                      srv->weight,
197                      srv->port,
198                      srv->target);
199     GNUNET_DNSPARSER_free_srv (srv);
200     return result;
201   }
202   case GNUNET_DNSPARSER_TYPE_TLSA: {
203     const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
204     char *tlsa_str;
205     char *hex;
206
207     if (data_size < sizeof (struct GNUNET_TUN_DnsTlsaRecord))
208       return NULL; /* malformed */
209     tlsa = data;
210     hex =
211       GNUNET_DNSPARSER_bin_to_hex (&tlsa[1],
212                                    data_size -
213                                      sizeof (struct GNUNET_TUN_DnsTlsaRecord));
214     if (0 == GNUNET_asprintf (&tlsa_str,
215                               "%u %u %u %s",
216                               (unsigned int) tlsa->usage,
217                               (unsigned int) tlsa->selector,
218                               (unsigned int) tlsa->matching_type,
219                               hex))
220     {
221       GNUNET_free (hex);
222       GNUNET_free (tlsa_str);
223       return NULL;
224     }
225     GNUNET_free (hex);
226     return tlsa_str;
227   }
228   case GNUNET_DNSPARSER_TYPE_CAA: { //RFC6844
229     const struct GNUNET_DNSPARSER_CaaRecord *caa;
230     char tag[15]; // between 1 and 15 bytes
231     char value[data_size];
232     char *caa_str;
233     if (data_size < sizeof (struct GNUNET_DNSPARSER_CaaRecord))
234       return NULL; /* malformed */
235     caa = data;
236     if ((1 > caa->tag_len) || (15 < caa->tag_len))
237       return NULL; /* malformed */
238     memset (tag, 0, sizeof (tag));
239     memset (value, 0, data_size);
240     memcpy (tag, &caa[1], caa->tag_len);
241     memcpy (value,
242             (char *) &caa[1] + caa->tag_len,
243             data_size - caa->tag_len - 2);
244     if (0 == GNUNET_asprintf (&caa_str,
245                               "%u %s %s",
246                               (unsigned int) caa->flags,
247                               tag,
248                               value))
249     {
250       GNUNET_free (caa_str);
251       return NULL;
252     }
253     return caa_str;
254   }
255   default:
256     return NULL;
257   }
258 }
259
260
261 /**
262  * Convert RFC 4394 Mnemonics to the corresponding integer values.
263  *
264  * @param mnemonic string to look up
265  * @return the value, 0 if not found
266  */
267 static unsigned int
268 rfc4398_mnemonic_to_value (const char *mnemonic)
269 {
270   static struct
271   {
272     const char *mnemonic;
273     unsigned int val;
274   } table[] = {{"PKIX", 1},
275                {"SPKI", 2},
276                {"PGP", 3},
277                {"IPKIX", 4},
278                {"ISPKI", 5},
279                {"IPGP", 6},
280                {"ACPKIX", 7},
281                {"IACPKIX", 8},
282                {"URI", 253},
283                {"OID", 254},
284                {NULL, 0}};
285   unsigned int i;
286
287   for (i = 0; NULL != table[i].mnemonic; i++)
288     if (0 == strcasecmp (mnemonic, table[i].mnemonic))
289       return table[i].val;
290   return 0;
291 }
292
293
294 /**
295  * Convert RFC 4034 algorithm types to the corresponding integer values.
296  *
297  * @param mnemonic string to look up
298  * @return the value, 0 if not found
299  */
300 static unsigned int
301 rfc4034_mnemonic_to_value (const char *mnemonic)
302 {
303   static struct
304   {
305     const char *mnemonic;
306     unsigned int val;
307   } table[] = {{"RSAMD5", 1},
308                {"DH", 2},
309                {"DSA", 3},
310                {"ECC", 4},
311                {"RSASHA1", 5},
312                {"INDIRECT", 252},
313                {"PRIVATEDNS", 253},
314                {"PRIVATEOID", 254},
315                {NULL, 0}};
316   unsigned int i;
317
318   for (i = 0; NULL != table[i].mnemonic; i++)
319     if (0 == strcasecmp (mnemonic, table[i].mnemonic))
320       return table[i].val;
321   return 0;
322 }
323
324
325 /**
326  * Convert human-readable version of a 'value' of a record to the binary
327  * representation.
328  *
329  * @param cls closure, unused
330  * @param type type of the record
331  * @param s human-readable string
332  * @param data set to value in binary encoding (will be allocated)
333  * @param data_size set to number of bytes in @a data
334  * @return #GNUNET_OK on success
335  */
336 static int
337 dns_string_to_value (void *cls,
338                      uint32_t type,
339                      const char *s,
340                      void **data,
341                      size_t *data_size)
342 {
343   struct in_addr value_a;
344   struct in6_addr value_aaaa;
345   struct GNUNET_TUN_DnsTlsaRecord *tlsa;
346
347   if (NULL == s)
348     return GNUNET_SYSERR;
349   switch (type)
350   {
351   case GNUNET_DNSPARSER_TYPE_A:
352     if (1 != inet_pton (AF_INET, s, &value_a))
353     {
354       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
355                   _ ("Unable to parse IPv4 address `%s'\n"),
356                   s);
357       return GNUNET_SYSERR;
358     }
359     *data = GNUNET_new (struct in_addr);
360     GNUNET_memcpy (*data, &value_a, sizeof (value_a));
361     *data_size = sizeof (value_a);
362     return GNUNET_OK;
363   case GNUNET_DNSPARSER_TYPE_NS: {
364     char nsbuf[256];
365     size_t off;
366
367     off = 0;
368     if (GNUNET_OK !=
369         GNUNET_DNSPARSER_builder_add_name (nsbuf, sizeof (nsbuf), &off, s))
370     {
371       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
372                   _ ("Failed to serialize NS record with value `%s'\n"),
373                   s);
374       return GNUNET_SYSERR;
375     }
376     *data_size = off;
377     *data = GNUNET_malloc (off);
378     GNUNET_memcpy (*data, nsbuf, off);
379     return GNUNET_OK;
380   }
381   case GNUNET_DNSPARSER_TYPE_CNAME: {
382     char cnamebuf[256];
383     size_t off;
384
385     off = 0;
386     if (GNUNET_OK != GNUNET_DNSPARSER_builder_add_name (cnamebuf,
387                                                         sizeof (cnamebuf),
388                                                         &off,
389                                                         s))
390     {
391       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392                   _ ("Failed to serialize CNAME record with value `%s'\n"),
393                   s);
394       return GNUNET_SYSERR;
395     }
396     *data_size = off;
397     *data = GNUNET_malloc (off);
398     GNUNET_memcpy (*data, cnamebuf, off);
399     return GNUNET_OK;
400   }
401   case GNUNET_DNSPARSER_TYPE_CERT: {
402     char *sdup;
403     const char *typep;
404     const char *keyp;
405     const char *algp;
406     const char *certp;
407     unsigned int type;
408     unsigned int key;
409     unsigned int alg;
410     size_t cert_size;
411     char *cert_data;
412     struct GNUNET_DNSPARSER_CertRecord cert;
413
414     sdup = GNUNET_strdup (s);
415     typep = strtok (sdup, " ");
416     if ((NULL == typep) ||
417         ((0 == (type = rfc4398_mnemonic_to_value (typep))) &&
418          ((1 != SSCANF (typep, "%u", &type)) || (type > UINT16_MAX))))
419     {
420       GNUNET_free (sdup);
421       return GNUNET_SYSERR;
422     }
423     keyp = strtok (NULL, " ");
424     if ((NULL == keyp) || (1 != SSCANF (keyp, "%u", &key)) ||
425         (key > UINT16_MAX))
426     {
427       GNUNET_free (sdup);
428       return GNUNET_SYSERR;
429     }
430     alg = 0;
431     algp = strtok (NULL, " ");
432     if ((NULL == algp) ||
433         ((0 == (type = rfc4034_mnemonic_to_value (typep))) &&
434          ((1 != sscanf (algp, "%u", &alg)) || (alg > UINT8_MAX))))
435     {
436       GNUNET_free (sdup);
437       return GNUNET_SYSERR;
438     }
439     certp = strtok (NULL, " ");
440     if ((NULL == certp) || (0 == strlen (certp)))
441     {
442       GNUNET_free (sdup);
443       return GNUNET_SYSERR;
444     }
445     cert_size = GNUNET_STRINGS_base64_decode (certp,
446                                               strlen (certp),
447                                               (void **) &cert_data);
448     GNUNET_free (sdup);
449     cert.cert_type = type;
450     cert.cert_tag = key;
451     cert.algorithm = alg;
452     cert.certificate_size = cert_size;
453     cert.certificate_data = cert_data;
454     {
455       char certbuf[cert_size + sizeof (struct GNUNET_TUN_DnsCertRecord)];
456       size_t off;
457
458       off = 0;
459       if (GNUNET_OK != GNUNET_DNSPARSER_builder_add_cert (certbuf,
460                                                           sizeof (certbuf),
461                                                           &off,
462                                                           &cert))
463       {
464         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
465                     _ ("Failed to serialize CERT record with %u bytes\n"),
466                     (unsigned int) cert_size);
467         GNUNET_free (cert_data);
468         return GNUNET_SYSERR;
469       }
470       *data_size = off;
471       *data = GNUNET_malloc (off);
472       GNUNET_memcpy (*data, certbuf, off);
473     }
474     GNUNET_free (cert_data);
475     return GNUNET_OK;
476   }
477   case GNUNET_DNSPARSER_TYPE_SOA: {
478     struct GNUNET_DNSPARSER_SoaRecord soa;
479     char soabuf[540];
480     char soa_rname[253 + 1];
481     char soa_mname[253 + 1];
482     unsigned int soa_serial;
483     unsigned int soa_refresh;
484     unsigned int soa_retry;
485     unsigned int soa_expire;
486     unsigned int soa_min;
487     size_t off;
488
489     if (7 != SSCANF (s,
490                      "rname=%253s mname=%253s %u,%u,%u,%u,%u",
491                      soa_rname,
492                      soa_mname,
493                      &soa_serial,
494                      &soa_refresh,
495                      &soa_retry,
496                      &soa_expire,
497                      &soa_min))
498     {
499       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
500                   _ ("Unable to parse SOA record `%s'\n"),
501                   s);
502       return GNUNET_SYSERR;
503     }
504     soa.mname = soa_mname;
505     soa.rname = soa_rname;
506     soa.serial = (uint32_t) soa_serial;
507     soa.refresh = (uint32_t) soa_refresh;
508     soa.retry = (uint32_t) soa_retry;
509     soa.expire = (uint32_t) soa_expire;
510     soa.minimum_ttl = (uint32_t) soa_min;
511     off = 0;
512     if (GNUNET_OK !=
513         GNUNET_DNSPARSER_builder_add_soa (soabuf, sizeof (soabuf), &off, &soa))
514     {
515       GNUNET_log (
516         GNUNET_ERROR_TYPE_ERROR,
517         _ ("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
518         soa_mname,
519         soa_rname);
520       return GNUNET_SYSERR;
521     }
522     *data_size = off;
523     *data = GNUNET_malloc (off);
524     GNUNET_memcpy (*data, soabuf, off);
525     return GNUNET_OK;
526   }
527   case GNUNET_DNSPARSER_TYPE_PTR: {
528     char ptrbuf[256];
529     size_t off;
530
531     off = 0;
532     if (GNUNET_OK !=
533         GNUNET_DNSPARSER_builder_add_name (ptrbuf, sizeof (ptrbuf), &off, s))
534     {
535       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
536                   _ ("Failed to serialize PTR record with value `%s'\n"),
537                   s);
538       return GNUNET_SYSERR;
539     }
540     *data_size = off;
541     *data = GNUNET_malloc (off);
542     GNUNET_memcpy (*data, ptrbuf, off);
543     return GNUNET_OK;
544   }
545   case GNUNET_DNSPARSER_TYPE_MX: {
546     struct GNUNET_DNSPARSER_MxRecord mx;
547     char mxbuf[258];
548     char mxhost[253 + 1];
549     unsigned int mx_pref;
550     size_t off;
551
552     if (2 != SSCANF (s, "%u,%253s", &mx_pref, mxhost))
553     {
554       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555                   _ ("Unable to parse MX record `%s'\n"),
556                   s);
557       return GNUNET_SYSERR;
558     }
559     mx.preference = (uint16_t) mx_pref;
560     mx.mxhost = mxhost;
561     off = 0;
562
563     if (GNUNET_OK !=
564         GNUNET_DNSPARSER_builder_add_mx (mxbuf, sizeof (mxbuf), &off, &mx))
565     {
566       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
567                   _ ("Failed to serialize MX record with hostname `%s'\n"),
568                   mxhost);
569       return GNUNET_SYSERR;
570     }
571     *data_size = off;
572     *data = GNUNET_malloc (off);
573     GNUNET_memcpy (*data, mxbuf, off);
574     return GNUNET_OK;
575   }
576   case GNUNET_DNSPARSER_TYPE_SRV: {
577     struct GNUNET_DNSPARSER_SrvRecord srv;
578     char srvbuf[270];
579     char srvtarget[253 + 1];
580     unsigned int priority;
581     unsigned int weight;
582     unsigned int port;
583     size_t off;
584
585     if (4 != SSCANF (s, "%u %u %u %253s", &priority, &weight, &port, srvtarget))
586     {
587       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
588                   _ ("Unable to parse SRV record `%s'\n"),
589                   s);
590       return GNUNET_SYSERR;
591     }
592     srv.priority = (uint16_t) priority;
593     srv.weight = (uint16_t) weight;
594     srv.port = (uint16_t) port;
595     srv.target = srvtarget;
596     off = 0;
597     if (GNUNET_OK !=
598         GNUNET_DNSPARSER_builder_add_srv (srvbuf, sizeof (srvbuf), &off, &srv))
599     {
600       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601                   _ ("Failed to serialize SRV record with target `%s'\n"),
602                   srvtarget);
603       return GNUNET_SYSERR;
604     }
605     *data_size = off;
606     *data = GNUNET_malloc (off);
607     GNUNET_memcpy (*data, srvbuf, off);
608     return GNUNET_OK;
609   }
610   case GNUNET_DNSPARSER_TYPE_TXT:
611     *data = GNUNET_strdup (s);
612     *data_size = strlen (s);
613     return GNUNET_OK;
614   case GNUNET_DNSPARSER_TYPE_AAAA:
615     if (1 != inet_pton (AF_INET6, s, &value_aaaa))
616     {
617       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
618                   _ ("Unable to parse IPv6 address `%s'\n"),
619                   s);
620       return GNUNET_SYSERR;
621     }
622     *data = GNUNET_new (struct in6_addr);
623     *data_size = sizeof (struct in6_addr);
624     GNUNET_memcpy (*data, &value_aaaa, sizeof (value_aaaa));
625     return GNUNET_OK;
626   case GNUNET_DNSPARSER_TYPE_TLSA: {
627     unsigned int usage;
628     unsigned int selector;
629     unsigned int matching_type;
630     size_t slen = strlen (s) + 1;
631     char hex[slen];
632
633     if (4 != SSCANF (s, "%u %u %u %s", &usage, &selector, &matching_type, hex))
634     {
635       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
636                   _ ("Unable to parse TLSA record string `%s'\n"),
637                   s);
638       *data_size = 0;
639       return GNUNET_SYSERR;
640     }
641
642     *data_size = sizeof (struct GNUNET_TUN_DnsTlsaRecord) + strlen (hex) / 2;
643     *data = tlsa = GNUNET_malloc (*data_size);
644     tlsa->usage = (uint8_t) usage;
645     tlsa->selector = (uint8_t) selector;
646     tlsa->matching_type = (uint8_t) matching_type;
647     if (strlen (hex) / 2 != GNUNET_DNSPARSER_hex_to_bin (hex, &tlsa[1]))
648     {
649       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
650                   _ ("Unable to parse TLSA record string `%s'\n"),
651                   s);
652       GNUNET_free (*data);
653       *data = NULL;
654       *data_size = 0;
655       return GNUNET_SYSERR;
656     }
657     return GNUNET_OK;
658   }
659   case GNUNET_DNSPARSER_TYPE_CAA: { //RFC6844
660     struct GNUNET_DNSPARSER_CaaRecord *caa;
661     unsigned int flags;
662     char tag[15]; //Max tag length 15
663     char value[strlen (s) + 1]; //Should be more than enough
664
665     if (3 != SSCANF (s, "%u %s %[^\n]", &flags, tag, value))
666     {
667       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
668                   _ ("Unable to parse CAA record string `%s'\n"),
669                   s);
670       *data_size = 0;
671       return GNUNET_SYSERR;
672     }
673     *data_size = sizeof (struct GNUNET_DNSPARSER_CaaRecord) + strlen (tag) +
674                  strlen (value);
675     *data = caa = GNUNET_malloc (*data_size);
676     caa->flags = flags;
677     memcpy (&caa[1], tag, strlen (tag));
678     caa->tag_len = strlen (tag);
679     memcpy ((char *) &caa[1] + caa->tag_len, value, strlen (value));
680     return GNUNET_OK;
681   }
682   default:
683     return GNUNET_SYSERR;
684   }
685 }
686
687
688 /**
689  * Mapping of record type numbers to human-readable
690  * record type names.
691  */
692 static struct
693 {
694   const char *name;
695   uint32_t number;
696 } name_map[] = {{"A", GNUNET_DNSPARSER_TYPE_A},
697                 {"NS", GNUNET_DNSPARSER_TYPE_NS},
698                 {"CNAME", GNUNET_DNSPARSER_TYPE_CNAME},
699                 {"SOA", GNUNET_DNSPARSER_TYPE_SOA},
700                 {"PTR", GNUNET_DNSPARSER_TYPE_PTR},
701                 {"MX", GNUNET_DNSPARSER_TYPE_MX},
702                 {"TXT", GNUNET_DNSPARSER_TYPE_TXT},
703                 {"AAAA", GNUNET_DNSPARSER_TYPE_AAAA},
704                 {"SRV", GNUNET_DNSPARSER_TYPE_SRV},
705                 {"TLSA", GNUNET_DNSPARSER_TYPE_TLSA},
706                 {"CERT", GNUNET_DNSPARSER_TYPE_CERT},
707                 {"CAA", GNUNET_DNSPARSER_TYPE_CAA},
708                 {NULL, UINT32_MAX}};
709
710
711 /**
712  * Convert a type name (i.e. "AAAA") to the corresponding number.
713  *
714  * @param cls closure, unused
715  * @param dns_typename name to convert
716  * @return corresponding number, UINT32_MAX on error
717  */
718 static uint32_t
719 dns_typename_to_number (void *cls, const char *dns_typename)
720 {
721   unsigned int i;
722
723   i = 0;
724   while ((NULL != name_map[i].name) &&
725          (0 != strcasecmp (dns_typename, name_map[i].name)))
726     i++;
727   return name_map[i].number;
728 }
729
730
731 /**
732  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
733  *
734  * @param cls closure, unused
735  * @param type number of a type to convert
736  * @return corresponding typestring, NULL on error
737  */
738 static const char *
739 dns_number_to_typename (void *cls, uint32_t type)
740 {
741   unsigned int i;
742
743   i = 0;
744   while ((NULL != name_map[i].name) && (type != name_map[i].number))
745     i++;
746   return name_map[i].name;
747 }
748
749
750 /**
751  * Entry point for the plugin.
752  *
753  * @param cls NULL
754  * @return the exported block API
755  */
756 void *
757 libgnunet_plugin_gnsrecord_dns_init (void *cls)
758 {
759   struct GNUNET_GNSRECORD_PluginFunctions *api;
760
761   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
762   api->value_to_string = &dns_value_to_string;
763   api->string_to_value = &dns_string_to_value;
764   api->typename_to_number = &dns_typename_to_number;
765   api->number_to_typename = &dns_number_to_typename;
766   return api;
767 }
768
769
770 /**
771  * Exit point from the plugin.
772  *
773  * @param cls the return value from #libgnunet_plugin_block_test_init
774  * @return NULL
775  */
776 void *
777 libgnunet_plugin_gnsrecord_dns_done (void *cls)
778 {
779   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
780
781   GNUNET_free (api);
782   return NULL;
783 }
784
785 /* end of plugin_gnsrecord_dns.c */