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