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