-rps service: prevent division by zero
[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
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 rfc4398_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     GNUNET_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       GNUNET_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       GNUNET_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 = rfc4398_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       alg = 0;
448       algp = strtok (NULL, " ");
449       if ( (NULL == algp) ||
450            ( (0 == (type = rfc4034_mnemonic_to_value (typep))) &&
451              ( (1 != sscanf (algp,
452                              "%u",
453                              &alg)) ||
454                (alg > UINT8_MAX) ) ) )
455       {
456         GNUNET_free (sdup);
457         return GNUNET_SYSERR;
458       }
459       certp = strtok (NULL, " ");
460       if ( (NULL == certp) ||
461            (0 == strlen (certp) ) )
462       {
463         GNUNET_free (sdup);
464         return GNUNET_SYSERR;
465       }
466       cert_size = GNUNET_STRINGS_base64_decode (certp,
467                                                 strlen (certp),
468                                                 &cert_data);
469       GNUNET_free (sdup);
470       cert.cert_type = type;
471       cert.cert_tag = key;
472       cert.algorithm = alg;
473       cert.certificate_size = cert_size;
474       cert.certificate_data = cert_data;
475       {
476         char certbuf[cert_size + sizeof (struct GNUNET_TUN_DnsCertRecord)];
477         size_t off;
478
479         off = 0;
480         if (GNUNET_OK !=
481             GNUNET_DNSPARSER_builder_add_cert (certbuf,
482                                                sizeof (certbuf),
483                                                &off,
484                                                &cert))
485         {
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;
491         }
492         *data_size = off;
493         *data = GNUNET_malloc (off);
494         GNUNET_memcpy (*data, certbuf, off);
495       }
496       GNUNET_free (cert_data);
497       return GNUNET_OK;
498     }
499   case GNUNET_DNSPARSER_TYPE_SOA:
500     {
501       struct GNUNET_DNSPARSER_SoaRecord soa;
502       char soabuf[540];
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;
510       size_t off;
511
512       if (7 != SSCANF (s,
513                        "rname=%253s mname=%253s %u,%u,%u,%u,%u",
514                        soa_rname,
515                        soa_mname,
516                        &soa_serial,
517                        &soa_refresh,
518                        &soa_retry,
519                        &soa_expire,
520                        &soa_min))
521       {
522         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
523              _("Unable to parse SOA record `%s'\n"),
524              s);
525         return GNUNET_SYSERR;
526       }
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;
534       off = 0;
535       if (GNUNET_OK !=
536           GNUNET_DNSPARSER_builder_add_soa (soabuf,
537                                             sizeof (soabuf),
538                                             &off,
539                                             &soa))
540       {
541         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
542                     _("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
543                     soa_mname,
544                     soa_rname);
545         return GNUNET_SYSERR;
546       }
547       *data_size = off;
548       *data = GNUNET_malloc (off);
549       GNUNET_memcpy (*data, soabuf, off);
550       return GNUNET_OK;
551     }
552   case GNUNET_DNSPARSER_TYPE_PTR:
553     {
554       char ptrbuf[256];
555       size_t off;
556
557       off = 0;
558       if (GNUNET_OK !=
559           GNUNET_DNSPARSER_builder_add_name (ptrbuf,
560                                              sizeof (ptrbuf),
561                                              &off,
562                                              s))
563       {
564         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
565                     _("Failed to serialize PTR record with value `%s'\n"),
566                     s);
567         return GNUNET_SYSERR;
568       }
569       *data_size = off;
570       *data = GNUNET_malloc (off);
571       GNUNET_memcpy (*data, ptrbuf, off);
572       return GNUNET_OK;
573     }
574   case GNUNET_DNSPARSER_TYPE_MX:
575     {
576       struct GNUNET_DNSPARSER_MxRecord mx;
577       char mxbuf[258];
578       char mxhost[253 + 1];
579       unsigned int mx_pref;
580       size_t off;
581
582       if (2 != SSCANF(s,
583                       "%u,%253s",
584                       &mx_pref,
585                       mxhost))
586       {
587         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
588              _("Unable to parse MX record `%s'\n"),
589              s);
590       return GNUNET_SYSERR;
591       }
592       mx.preference = (uint16_t) mx_pref;
593       mx.mxhost = mxhost;
594       off = 0;
595
596       if (GNUNET_OK !=
597           GNUNET_DNSPARSER_builder_add_mx (mxbuf,
598                                            sizeof (mxbuf),
599                                            &off,
600                                            &mx))
601       {
602         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603              _("Failed to serialize MX record with hostname `%s'\n"),
604              mxhost);
605         return GNUNET_SYSERR;
606       }
607       *data_size = off;
608       *data = GNUNET_malloc (off);
609       GNUNET_memcpy (*data, mxbuf, off);
610       return GNUNET_OK;
611     }
612   case GNUNET_DNSPARSER_TYPE_SRV:
613     {
614       struct GNUNET_DNSPARSER_SrvRecord srv;
615       char srvbuf[270];
616       char srvtarget[253 + 1];
617       unsigned int priority;
618       unsigned int weight;
619       unsigned int port;
620       size_t off;
621
622       if (4 != SSCANF(s,
623                       "%u %u %u %253s",
624                       &priority,
625                       &weight,
626                       &port,
627                       srvtarget))
628       {
629         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630              _("Unable to parse SRV record `%s'\n"),
631              s);
632         return GNUNET_SYSERR;
633       }
634       srv.priority = (uint16_t) priority;
635       srv.weight = (uint16_t) weight;
636       srv.port = (uint16_t) port;
637       srv.target = srvtarget;
638       off = 0;
639       if (GNUNET_OK !=
640           GNUNET_DNSPARSER_builder_add_srv (srvbuf,
641                                             sizeof (srvbuf),
642                                             &off,
643                                             &srv))
644       {
645         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
646                     _("Failed to serialize SRV record with target `%s'\n"),
647                     srvtarget);
648         return GNUNET_SYSERR;
649       }
650       *data_size = off;
651       *data = GNUNET_malloc (off);
652       GNUNET_memcpy (*data, srvbuf, off);
653       return GNUNET_OK;
654     }
655   case GNUNET_DNSPARSER_TYPE_TXT:
656     *data = GNUNET_strdup (s);
657     *data_size = strlen (s);
658     return GNUNET_OK;
659   case GNUNET_DNSPARSER_TYPE_AAAA:
660     if (1 != inet_pton (AF_INET6, s, &value_aaaa))
661     {
662       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663            _("Unable to parse IPv6 address `%s'\n"),
664            s);
665       return GNUNET_SYSERR;
666     }
667     *data = GNUNET_new (struct in6_addr);
668     *data_size = sizeof (struct in6_addr);
669     GNUNET_memcpy (*data, &value_aaaa, sizeof (value_aaaa));
670     return GNUNET_OK;
671   case GNUNET_DNSPARSER_TYPE_TLSA:
672     {
673       unsigned int usage;
674       unsigned int selector;
675       unsigned int matching_type;
676       size_t slen = strlen (s) + 1;
677       char hex[slen];
678
679       if (4 != SSCANF (s,
680                        "%u %u %u %s",
681                        &usage,
682                        &selector,
683                        &matching_type,
684                        hex))
685       {
686         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
687                     _("Unable to parse TLSA record string `%s'\n"),
688                     s);
689         *data_size = 0;
690         return GNUNET_SYSERR;
691       }
692
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,
700                                        &tlsa[1]))
701       {
702         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703                     _("Unable to parse TLSA record string `%s'\n"),
704                     s);
705         GNUNET_free (*data);
706         *data = NULL;
707         *data_size = 0;
708         return GNUNET_SYSERR;
709       }
710       return GNUNET_OK;
711     }
712   default:
713     return GNUNET_SYSERR;
714   }
715 }
716
717
718 /**
719  * Mapping of record type numbers to human-readable
720  * record type names.
721  */
722 static struct {
723   const char *name;
724   uint32_t number;
725 } name_map[] = {
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 },
737   { NULL, UINT32_MAX }
738 };
739
740
741 /**
742  * Convert a type name (i.e. "AAAA") to the corresponding number.
743  *
744  * @param cls closure, unused
745  * @param dns_typename name to convert
746  * @return corresponding number, UINT32_MAX on error
747  */
748 static uint32_t
749 dns_typename_to_number (void *cls,
750                         const char *dns_typename)
751 {
752   unsigned int i;
753
754   i=0;
755   while ( (NULL != name_map[i].name) &&
756           (0 != strcasecmp (dns_typename, name_map[i].name)) )
757     i++;
758   return name_map[i].number;
759 }
760
761
762 /**
763  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
764  *
765  * @param cls closure, unused
766  * @param type number of a type to convert
767  * @return corresponding typestring, NULL on error
768  */
769 static const char *
770 dns_number_to_typename (void *cls,
771                         uint32_t type)
772 {
773   unsigned int i;
774
775   i=0;
776   while ( (NULL != name_map[i].name) &&
777           (type != name_map[i].number) )
778     i++;
779   return name_map[i].name;
780 }
781
782
783 /**
784  * Entry point for the plugin.
785  *
786  * @param cls NULL
787  * @return the exported block API
788  */
789 void *
790 libgnunet_plugin_gnsrecord_dns_init (void *cls)
791 {
792   struct GNUNET_GNSRECORD_PluginFunctions *api;
793
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;
799   return api;
800 }
801
802
803 /**
804  * Exit point from the plugin.
805  *
806  * @param cls the return value from #libgnunet_plugin_block_test_init
807  * @return NULL
808  */
809 void *
810 libgnunet_plugin_gnsrecord_dns_done (void *cls)
811 {
812   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
813
814   GNUNET_free (api);
815   return NULL;
816 }
817
818 /* end of plugin_gnsrecord_dns.c */