- cleanup dead code
[oweals/gnunet.git] / src / namestore / namestore_api_common.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009-2013 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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file namestore/namestore_api_common.c
23  * @brief API to access the NAMESTORE service
24  * @author Martin Schanzenbach
25  * @author Matthias Wachs
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_arm_service.h"
33 #include "gnunet_conversation_service.h"
34 #include "gnunet_namestore_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_tun_lib.h"
37 #include "namestore.h"
38
39
40 #define LOG(kind,...) GNUNET_log_from (kind, "namestore-api",__VA_ARGS__)
41
42 GNUNET_NETWORK_STRUCT_BEGIN
43
44
45 /**
46  * Internal format of a record in the serialized form.
47  */
48 struct NetworkRecord
49 {
50
51   /**
52    * Expiration time for the DNS record; relative or absolute depends
53    * on 'flags', network byte order.
54    */
55   uint64_t expiration_time GNUNET_PACKED;
56
57   /**
58    * Number of bytes in 'data', network byte order.
59    */
60   uint32_t data_size GNUNET_PACKED;
61
62   /**
63    * Type of the GNS/DNS record, network byte order.
64    */
65   uint32_t record_type GNUNET_PACKED;
66
67   /**
68    * Flags for the record, network byte order.
69    */
70   uint32_t flags GNUNET_PACKED;
71
72 };
73
74 GNUNET_NETWORK_STRUCT_END
75
76 /**
77  * Convert a UTF-8 string to UTF-8 lowercase
78  * @param src source string
79  * @return converted result
80  */
81 char *
82 GNUNET_NAMESTORE_normalize_string (const char *src)
83 {
84   GNUNET_assert (NULL != src);
85   char *res = strdup (src);
86   /* normalize */
87   GNUNET_STRINGS_utf8_tolower(src, &res);
88   return res;
89 }
90
91
92 /**
93  * Convert a zone key to a string (for printing debug messages).
94  * This is one of the very few calls in the entire API that is
95  * NOT reentrant!
96  *
97  * @param z the zone key
98  * @return string form; will be overwritten by next call to #GNUNET_NAMESTORE_z2s
99  */
100 const char *
101 GNUNET_NAMESTORE_z2s (const struct GNUNET_CRYPTO_EccPublicSignKey *z)
102 {
103   static char buf[sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) * 8];
104   char *end;
105
106   end = GNUNET_STRINGS_data_to_string ((const unsigned char *) z,
107                                        sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
108                                        buf, sizeof (buf));
109   if (NULL == end)
110   {
111     GNUNET_break (0);
112     return NULL;
113   }
114   *end = '\0';
115   return buf;
116 }
117
118
119 /**
120  * Calculate how many bytes we will need to serialize the given
121  * records.
122  *
123  * @param rd_count number of records in the rd array
124  * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
125  * @return the required size to serialize
126  */
127 size_t
128 GNUNET_NAMESTORE_records_get_size (unsigned int rd_count,
129                                    const struct GNUNET_NAMESTORE_RecordData *rd)
130 {
131   unsigned int i;
132   size_t ret;
133
134   ret = sizeof (struct NetworkRecord) * rd_count;
135   for (i=0;i<rd_count;i++)
136   {
137     GNUNET_assert ((ret + rd[i].data_size) >= ret);
138     ret += rd[i].data_size;
139   }
140   return ret;
141 }
142
143
144 /**
145  * Serialize the given records to the given destination buffer.
146  *
147  * @param rd_count number of records in the rd array
148  * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
149  * @param dest_size size of the destination array
150  * @param dest where to write the result
151  * @return the size of serialized records, -1 if records do not fit
152  */
153 ssize_t
154 GNUNET_NAMESTORE_records_serialize (unsigned int rd_count,
155                                     const struct GNUNET_NAMESTORE_RecordData *rd,
156                                     size_t dest_size,
157                                     char *dest)
158 {
159   struct NetworkRecord rec;
160   unsigned int i;
161   size_t off;
162
163   off = 0;
164   for (i=0;i<rd_count;i++)
165   {
166     LOG (GNUNET_ERROR_TYPE_DEBUG,
167          "Serializing record %u with flags %d and expiration time %llu\n",
168          i,
169          rd[i].flags,
170          (unsigned long long) rd[i].expiration_time);
171     rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
172     rec.data_size = htonl ((uint32_t) rd[i].data_size);
173     rec.record_type = htonl (rd[i].record_type);
174     rec.flags = htonl (rd[i].flags);
175     if (off + sizeof (rec) > dest_size)
176       return -1;
177     memcpy (&dest[off], &rec, sizeof (rec));
178     off += sizeof (rec);
179     if (off + rd[i].data_size > dest_size)
180       return -1;
181     memcpy (&dest[off], rd[i].data, rd[i].data_size);
182     off += rd[i].data_size;
183   }
184   return off;
185 }
186
187
188 /**
189  * Compares if two records are equal (ignoring flags such
190  * as authority, private and pending, but not relative vs.
191  * absolute expiration time).
192  *
193  * @param a record
194  * @param b record
195  * @return #GNUNET_YES if the records are equal or #GNUNET_NO if they are not
196  */
197 int
198 GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a,
199                               const struct GNUNET_NAMESTORE_RecordData *b)
200 {
201   LOG (GNUNET_ERROR_TYPE_DEBUG,
202        "Comparing records\n");
203   if (a->record_type != b->record_type)
204   {
205     LOG (GNUNET_ERROR_TYPE_DEBUG,
206          "Record type %lu != %lu\n", a->record_type, b->record_type);
207     return GNUNET_NO;
208   }
209   if ((a->expiration_time != b->expiration_time) &&
210       ((a->expiration_time != 0) && (b->expiration_time != 0)))
211   {
212     LOG (GNUNET_ERROR_TYPE_DEBUG,
213          "Expiration time %llu != %llu\n",
214          a->expiration_time,
215          b->expiration_time);
216     return GNUNET_NO;
217   }
218   if ((a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS)
219        != (b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS))
220   {
221     LOG (GNUNET_ERROR_TYPE_DEBUG,
222          "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
223          a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS, b->flags,
224          b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS);
225     return GNUNET_NO;
226   }
227   if (a->data_size != b->data_size)
228   {
229     LOG (GNUNET_ERROR_TYPE_DEBUG,
230          "Data size %lu != %lu\n",
231          a->data_size,
232          b->data_size);
233     return GNUNET_NO;
234   }
235   if (0 != memcmp (a->data, b->data, a->data_size))
236   {
237     LOG (GNUNET_ERROR_TYPE_DEBUG,
238          "Data contents do not match\n");
239     return GNUNET_NO;
240   }
241   LOG (GNUNET_ERROR_TYPE_DEBUG,
242        "Records are equal\n");
243   return GNUNET_YES;
244 }
245
246
247 /**
248  * Deserialize the given records to the given destination.
249  *
250  * @param len size of the serialized record data
251  * @param src the serialized record data
252  * @param rd_count number of records in the rd array
253  * @param dest where to put the data
254  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
255  */
256 int
257 GNUNET_NAMESTORE_records_deserialize (size_t len,
258                                       const char *src,
259                                       unsigned int rd_count,
260                                       struct GNUNET_NAMESTORE_RecordData *dest)
261 {
262   struct NetworkRecord rec;
263   unsigned int i;
264   size_t off;
265
266   off = 0;
267   for (i=0;i<rd_count;i++)
268   {
269     if (off + sizeof (rec) > len)
270       return GNUNET_SYSERR;
271     memcpy (&rec, &src[off], sizeof (rec));
272     dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
273     dest[i].data_size = ntohl ((uint32_t) rec.data_size);
274     dest[i].record_type = ntohl (rec.record_type);
275     dest[i].flags = ntohl (rec.flags);
276     off += sizeof (rec);
277     if (off + dest[i].data_size > len)
278       return GNUNET_SYSERR;
279     dest[i].data = &src[off];
280     off += dest[i].data_size;
281     LOG (GNUNET_ERROR_TYPE_DEBUG,
282          "Deserialized record %u with flags %d and expiration time %llu\n",
283          i,
284          dest[i].flags,
285          (unsigned long long) dest[i].expiration_time);
286   }
287   return GNUNET_OK;
288 }
289
290
291 /**
292  * Returns the expiration time of the given block of records. The block
293  * expiration time is the expiration time of the record with smallest
294  * expiration time.
295  *
296  * @param rd_count number of records given in @a rd
297  * @param rd array of records
298  * @return absolute expiration time
299  */
300 struct GNUNET_TIME_Absolute
301 GNUNET_NAMESTORE_record_get_expiration_time (unsigned int rd_count,
302                                              const struct GNUNET_NAMESTORE_RecordData *rd)
303 {
304   unsigned int c;
305   struct GNUNET_TIME_Absolute expire;
306   struct GNUNET_TIME_Absolute at;
307   struct GNUNET_TIME_Relative rt;
308
309   if (NULL == rd)
310     return GNUNET_TIME_UNIT_ZERO_ABS;
311   expire = GNUNET_TIME_UNIT_FOREVER_ABS;
312   for (c = 0; c < rd_count; c++)
313   {
314     if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
315     {
316       rt.rel_value_us = rd[c].expiration_time;
317       at = GNUNET_TIME_relative_to_absolute (rt);
318     }
319     else
320     {
321       at.abs_value_us = rd[c].expiration_time;
322     }
323     expire = GNUNET_TIME_absolute_min (at, expire);
324   }
325   LOG (GNUNET_ERROR_TYPE_DEBUG,
326        "Determined expiration time for block with %u records to be %s\n",
327        rd_count,
328        GNUNET_STRINGS_absolute_time_to_string (expire));
329   return expire;
330 }
331
332
333 /**
334  * Derive session key and iv from label and public key.
335  *
336  * @param iv initialization vector to initialize
337  * @param skey session key to initialize
338  * @param label label to use for KDF
339  * @param pub public key to use for KDF
340  */
341 static void
342 derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
343                       struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
344                       const char *label,
345                       const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
346 {
347   static const char ctx_key[] = "gns-aes-ctx-key";
348   static const char ctx_iv[] = "gns-aes-ctx-iv";
349
350   GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
351                      pub, sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
352                      label, strlen (label),
353                      ctx_key, strlen (ctx_key),
354                      NULL, 0);
355   GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
356                      pub, sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
357                      label, strlen (label),
358                      ctx_iv, strlen (ctx_iv),
359                      NULL, 0);
360 }
361
362
363 /**
364  * Sign name and records
365  *
366  * @param key the private key
367  * @param expire block expiration
368  * @param label the name for the records
369  * @param rd record data
370  * @param rd_count number of records
371  * @return NULL on error (block too large)
372  */
373 struct GNUNET_NAMESTORE_Block *
374 GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EccPrivateKey *key,
375                                struct GNUNET_TIME_Absolute expire,
376                                const char *label,
377                                const struct GNUNET_NAMESTORE_RecordData *rd,
378                                unsigned int rd_count)
379 {
380   size_t payload_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
381   char payload[sizeof (uint32_t) + payload_len];
382   struct GNUNET_NAMESTORE_Block *block;
383   struct GNUNET_CRYPTO_EccPublicSignKey pkey;
384   struct GNUNET_CRYPTO_EccPrivateKey *dkey;
385   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
386   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
387   uint32_t rd_count_nbo;
388
389   if (payload_len > GNUNET_NAMESTORE_MAX_VALUE_SIZE)
390     return NULL;
391   rd_count_nbo = htonl (rd_count);
392   memcpy (payload, &rd_count_nbo, sizeof (uint32_t));
393   GNUNET_assert (payload_len ==
394                  GNUNET_NAMESTORE_records_serialize (rd_count, rd,
395                                                      payload_len, &payload[sizeof (uint32_t)]));
396   block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) +
397                          sizeof (uint32_t) + payload_len);
398   block->purpose.size = htonl (sizeof (uint32_t) + payload_len +
399                                sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
400                                sizeof (struct GNUNET_TIME_AbsoluteNBO));
401   block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
402   block->expiration_time = GNUNET_TIME_absolute_hton (expire);
403   dkey = GNUNET_CRYPTO_ecc_key_derive (key,
404                                        label,
405                                        "gns");
406   GNUNET_CRYPTO_ecc_key_get_public_for_signature (dkey,
407                                     &block->derived_key);
408   GNUNET_CRYPTO_ecc_key_get_public_for_signature (key,
409                                     &pkey);
410   derive_block_aes_key (&iv, &skey, label, &pkey);
411   GNUNET_break (payload_len + sizeof (uint32_t) ==
412                 GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t),
413                                            &skey, &iv,
414                                            &block[1]));
415   if (GNUNET_OK !=
416       GNUNET_CRYPTO_ecc_sign (dkey,
417                               &block->purpose,
418                               &block->signature))
419   {
420     GNUNET_break (0);
421     GNUNET_free (dkey);
422     GNUNET_free (block);
423     return NULL;
424   }
425   GNUNET_free (dkey);
426   return block;
427 }
428
429
430 /**
431  * Check if a signature is valid.  This API is used by the GNS Block
432  * to validate signatures received from the network.
433  *
434  * @param block block to verify
435  * @return #GNUNET_OK if the signature is valid
436  */
437 int
438 GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block)
439 {
440   return GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
441                                    &block->purpose,
442                                    &block->signature,
443                                    &block->derived_key);
444 }
445
446
447 /**
448  * Decrypt block.
449  *
450  * @param block block to decrypt
451  * @param zone_key public key of the zone
452  * @param label the name for the records
453  * @param proc function to call with the result
454  * @param proc_cls closure for proc
455  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
456  *        not well-formed
457  */
458 int
459 GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
460                                 const struct GNUNET_CRYPTO_EccPublicSignKey *zone_key,
461                                 const char *label,
462                                 GNUNET_NAMESTORE_RecordCallback proc,
463                                 void *proc_cls)
464 {
465   size_t payload_len = ntohl (block->purpose.size) -
466     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) -
467     sizeof (struct GNUNET_TIME_AbsoluteNBO);
468   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
469   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
470
471   if (ntohl (block->purpose.size) <
472       sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
473       sizeof (struct GNUNET_TIME_AbsoluteNBO))
474   {
475     GNUNET_break_op (0);
476     return GNUNET_SYSERR;
477   }
478   derive_block_aes_key (&iv, &skey, label, zone_key);
479   {
480     char payload[payload_len];
481     uint32_t rd_count;
482
483     GNUNET_break (payload_len ==
484                   GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
485                                              &skey, &iv,
486                                              payload));
487     memcpy (&rd_count,
488             payload,
489             sizeof (uint32_t));
490     rd_count = ntohl (rd_count);
491     if (rd_count > 2048)
492     {
493       /* limit to sane value */
494       GNUNET_break_op (0);
495       return GNUNET_SYSERR;
496     }
497     {
498       struct GNUNET_NAMESTORE_RecordData rd[rd_count];
499
500       if (GNUNET_OK !=
501           GNUNET_NAMESTORE_records_deserialize (payload_len - sizeof (uint32_t),
502                                                 &payload[sizeof (uint32_t)],
503                                                 rd_count,
504                                                 rd))
505       {
506         GNUNET_break_op (0);
507         return GNUNET_SYSERR;
508       }
509       if (NULL != proc)
510         proc (proc_cls, rd_count, (0 != rd_count) ? rd : NULL);
511     }
512   }
513   return GNUNET_OK;
514 }
515
516
517 /**
518  * Convert the 'value' of a record to a string.
519  *
520  * @param type type of the record
521  * @param data value in binary encoding
522  * @param data_size number of bytes in @a data
523  * @return NULL on error, otherwise human-readable representation of the value
524  */
525 char *
526 GNUNET_NAMESTORE_value_to_string (uint32_t type,
527                                   const void *data,
528                                   size_t data_size)
529 {
530   const char *cdata;
531   char* result;
532   char tmp[INET6_ADDRSTRLEN];
533
534   switch (type)
535   {
536   case 0:
537     return NULL;
538   case GNUNET_DNSPARSER_TYPE_A:
539     if (data_size != sizeof (struct in_addr))
540       return NULL;
541     if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
542       return NULL;
543     return GNUNET_strdup (tmp);
544   case GNUNET_DNSPARSER_TYPE_NS:
545     {
546       char *ns;
547       size_t off;
548
549       off = 0;
550       ns = GNUNET_DNSPARSER_parse_name (data,
551                                         data_size,
552                                         &off);
553       if ( (NULL == ns) ||
554            (off != data_size) )
555       {
556         GNUNET_break_op (0);
557         return NULL;
558       }
559       return ns;
560     }
561   case GNUNET_DNSPARSER_TYPE_CNAME:
562     {
563       char *cname;
564       size_t off;
565
566       off = 0;
567       cname = GNUNET_DNSPARSER_parse_name (data,
568                                            data_size,
569                                            &off);
570       if ( (NULL == cname) ||
571            (off != data_size) )
572       {
573         GNUNET_break_op (0);
574         return NULL;
575       }
576       return cname;
577     }
578   case GNUNET_DNSPARSER_TYPE_SOA:
579     {
580       struct GNUNET_DNSPARSER_SoaRecord *soa;
581       size_t off;
582
583       off = 0;
584       soa = GNUNET_DNSPARSER_parse_soa (data,
585                                         data_size,
586                                         &off);
587       if ( (NULL == soa) ||
588            (off != data_size) )
589       {
590         GNUNET_break_op (0);
591         return NULL;
592       }
593       GNUNET_asprintf (&result,
594                        "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
595                        soa->rname,
596                        soa->mname,
597                        soa->serial,
598                        soa->refresh,
599                        soa->retry,
600                        soa->expire,
601                        soa->minimum_ttl);
602       GNUNET_DNSPARSER_free_soa (soa);
603       return result;
604     }
605   case GNUNET_DNSPARSER_TYPE_PTR:
606     {
607       char *ptr;
608       size_t off;
609
610       off = 0;
611       ptr = GNUNET_DNSPARSER_parse_name (data,
612                                            data_size,
613                                            &off);
614       if ( (NULL == ptr) ||
615            (off != data_size) )
616       {
617         GNUNET_break_op (0);
618         return NULL;
619       }
620       return ptr;
621     }
622   case GNUNET_DNSPARSER_TYPE_MX:
623     {
624       struct GNUNET_DNSPARSER_MxRecord *mx;
625       size_t off;
626
627       off = 0;
628       mx = GNUNET_DNSPARSER_parse_mx (data,
629                                       data_size,
630                                       &off);
631       if ( (NULL == mx) ||
632            (off != data_size) )
633       {
634         GNUNET_break_op (0);
635         return NULL;
636       }
637       GNUNET_asprintf (&result,
638                        "%hu,%s",
639                        mx->preference,
640                        mx->mxhost);
641       GNUNET_DNSPARSER_free_mx (mx);
642       return result;
643     }
644   case GNUNET_DNSPARSER_TYPE_TXT:
645     return GNUNET_strndup (data, data_size);
646   case GNUNET_DNSPARSER_TYPE_AAAA:
647     if (data_size != sizeof (struct in6_addr))
648       return NULL;
649     if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
650       return NULL;
651     return GNUNET_strdup (tmp);
652   case GNUNET_NAMESTORE_TYPE_PKEY:
653     if (data_size != sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))
654       return NULL;
655     return GNUNET_CRYPTO_ecc_public_sign_key_to_string (data);
656   case GNUNET_NAMESTORE_TYPE_PHONE:
657     {
658       const struct GNUNET_CONVERSATION_PhoneRecord *pr;
659       char *ret;
660       char *pkey;
661
662       if (data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord))
663         return NULL;
664       pr = data;
665       if (0 != ntohl (pr->version))
666         return NULL;
667       pkey = GNUNET_CRYPTO_ecc_public_sign_key_to_string (&pr->peer.public_key);
668       GNUNET_asprintf (&ret,
669                        "%u-%s",
670                        ntohl (pr->line),
671                        pkey);
672       GNUNET_free (pkey);
673       return ret;
674     }
675   case GNUNET_NAMESTORE_TYPE_PSEU:
676     return GNUNET_strndup (data, data_size);
677   case GNUNET_NAMESTORE_TYPE_LEHO:
678     return GNUNET_strndup (data, data_size);
679   case GNUNET_NAMESTORE_TYPE_VPN:
680     {
681       const struct GNUNET_TUN_GnsVpnRecord *vpn;
682       char* vpn_str;
683
684       cdata = data;
685       if ( (data_size <= sizeof (struct GNUNET_TUN_GnsVpnRecord)) ||
686            ('\0' != cdata[data_size - 1]) )
687         return NULL; /* malformed */
688       vpn = data;
689       if (0 == GNUNET_asprintf (&vpn_str, "%u %s %s",
690                                 (unsigned int) ntohs (vpn->proto),
691                                 (const char*) GNUNET_i2s_full (&vpn->peer),
692                                 (const char*) &vpn[1]))
693       {
694         GNUNET_free (vpn_str);
695         return NULL;
696       }
697       return vpn_str;
698     }
699   case GNUNET_NAMESTORE_TYPE_GNS2DNS:
700     {
701       char *ns;
702       size_t off;
703
704       off = 0;
705       ns = GNUNET_DNSPARSER_parse_name (data,
706                                         data_size,
707                                         &off);
708       if ( (NULL == ns) ||
709            (off != data_size) )
710       {
711         GNUNET_break_op (0);
712         return NULL;
713       }
714       return ns;
715     }
716   case GNUNET_DNSPARSER_TYPE_SRV:
717     {
718       struct GNUNET_DNSPARSER_SrvRecord *srv;
719       size_t off;
720
721       off = 0;
722       srv = GNUNET_DNSPARSER_parse_srv ("+", /* FIXME: is this OK? */
723                                         data,
724                                         data_size,
725                                         &off);
726       if ( (NULL == srv) ||
727            (off != data_size) )
728       {
729         GNUNET_break_op (0);
730         return NULL;
731       }
732       GNUNET_asprintf (&result,
733                        "%d %d %d _%s._%s.%s",
734                        srv->priority,
735                        srv->weight,
736                        srv->port,
737                        srv->service,
738                        srv->proto,
739                        srv->domain_name);
740       GNUNET_DNSPARSER_free_srv (srv);
741       return result;
742     }
743   case GNUNET_DNSPARSER_TYPE_TLSA:
744     {
745       const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
746       char* tlsa_str;
747
748       cdata = data;
749       if ( (data_size <= sizeof (struct GNUNET_TUN_DnsTlsaRecord)) ||
750            ('\0' != cdata[data_size - 1]) )
751         return NULL; /* malformed */
752       tlsa = data;
753       if (0 == GNUNET_asprintf (&tlsa_str,
754                                 "%c %c %c %s",
755                                 tlsa->usage,
756                                 tlsa->selector,
757                                 tlsa->matching_type,
758                                 (const char *) &tlsa[1]))
759       {
760         GNUNET_free (tlsa_str);
761         return NULL;
762       }
763       return tlsa_str;
764     }
765   default:
766     GNUNET_break (0);
767   }
768   GNUNET_break (0); // not implemented
769   return NULL;
770 }
771
772
773 /**
774  * Convert human-readable version of a 'value' of a record to the binary
775  * representation.
776  *
777  * @param type type of the record
778  * @param s human-readable string
779  * @param data set to value in binary encoding (will be allocated)
780  * @param data_size set to number of bytes in @a data
781  * @return #GNUNET_OK on success
782  */
783 int
784 GNUNET_NAMESTORE_string_to_value (uint32_t type,
785                                   const char *s,
786                                   void **data,
787                                   size_t *data_size)
788 {
789   struct in_addr value_a;
790   struct in6_addr value_aaaa;
791   struct GNUNET_CRYPTO_EccPublicSignKey pkey;
792   struct GNUNET_TUN_GnsVpnRecord *vpn;
793   struct GNUNET_TUN_DnsTlsaRecord *tlsa;
794   char s_peer[103 + 1];
795   char s_serv[253 + 1];
796   unsigned int proto;
797
798   if (NULL == s)
799     return GNUNET_SYSERR;
800   switch (type)
801   {
802   case 0:
803     LOG (GNUNET_ERROR_TYPE_ERROR,
804          _("Unsupported record type %d\n"),
805          (int) type);
806     return GNUNET_SYSERR;
807   case GNUNET_DNSPARSER_TYPE_A:
808     if (1 != inet_pton (AF_INET, s, &value_a))
809     {
810       LOG (GNUNET_ERROR_TYPE_ERROR,
811            _("Unable to parse IPv4 address `%s'\n"),
812            s);
813       return GNUNET_SYSERR;
814     }
815     *data = GNUNET_malloc (sizeof (struct in_addr));
816     memcpy (*data, &value_a, sizeof (value_a));
817     *data_size = sizeof (value_a);
818     return GNUNET_OK;
819   case GNUNET_DNSPARSER_TYPE_NS:
820     {
821       char nsbuf[256];
822       size_t off;
823
824       off = 0;
825       if (GNUNET_OK !=
826           GNUNET_DNSPARSER_builder_add_name (nsbuf,
827                                              sizeof (nsbuf),
828                                              &off,
829                                              s))
830       {
831         LOG (GNUNET_ERROR_TYPE_ERROR,
832              _("Failed to serialize NS record with value `%s'\n"),
833              s);
834         return GNUNET_SYSERR;
835       }
836       *data_size = off;
837       *data = GNUNET_malloc (off);
838       memcpy (*data, nsbuf, off);
839       return GNUNET_OK;
840     }
841   case GNUNET_DNSPARSER_TYPE_CNAME:
842     {
843       char cnamebuf[256];
844       size_t off;
845
846       off = 0;
847       if (GNUNET_OK !=
848           GNUNET_DNSPARSER_builder_add_name (cnamebuf,
849                                              sizeof (cnamebuf),
850                                              &off,
851                                              s))
852       {
853         LOG (GNUNET_ERROR_TYPE_ERROR,
854              _("Failed to serialize CNAME record with value `%s'\n"),
855              s);
856         return GNUNET_SYSERR;
857       }
858       *data_size = off;
859       *data = GNUNET_malloc (off);
860       memcpy (*data, cnamebuf, off);
861       return GNUNET_OK;
862     }
863   case GNUNET_DNSPARSER_TYPE_SOA:
864     {
865       struct GNUNET_DNSPARSER_SoaRecord soa;
866       char soabuf[540];
867       char soa_rname[253 + 1];
868       char soa_mname[253 + 1];
869       unsigned int soa_serial;
870       unsigned int soa_refresh;
871       unsigned int soa_retry;
872       unsigned int soa_expire;
873       unsigned int soa_min;
874       size_t off;
875
876       if (7 != SSCANF (s,
877                        "rname=%253s mname=%253s %u,%u,%u,%u,%u",
878                        soa_rname, soa_mname,
879                        &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min))
880       {
881         LOG (GNUNET_ERROR_TYPE_ERROR,
882              _("Unable to parse SOA record `%s'\n"),
883              s);
884         return GNUNET_SYSERR;
885       }
886       soa.mname = soa_mname;
887       soa.rname = soa_rname;
888       soa.serial = (uint32_t) soa_serial;
889       soa.refresh =(uint32_t)  soa_refresh;
890       soa.retry = (uint32_t) soa_retry;
891       soa.expire = (uint32_t) soa_expire;
892       soa.minimum_ttl = (uint32_t) soa_min;
893       off = 0;
894       if (GNUNET_OK !=
895           GNUNET_DNSPARSER_builder_add_soa (soabuf,
896                                             sizeof (soabuf),
897                                             &off,
898                                             &soa))
899       {
900         LOG (GNUNET_ERROR_TYPE_ERROR,
901              _("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
902              soa_mname,
903              soa_rname);
904         return GNUNET_SYSERR;
905       }
906       *data_size = off;
907       *data = GNUNET_malloc (off);
908       memcpy (*data, soabuf, off);
909       return GNUNET_OK;
910     }
911   case GNUNET_DNSPARSER_TYPE_PTR:
912     {
913       char ptrbuf[256];
914       size_t off;
915
916       off = 0;
917       if (GNUNET_OK !=
918           GNUNET_DNSPARSER_builder_add_name (ptrbuf,
919                                              sizeof (ptrbuf),
920                                              &off,
921                                              s))
922       {
923         LOG (GNUNET_ERROR_TYPE_ERROR,
924              _("Failed to serialize PTR record with value `%s'\n"),
925              s);
926         return GNUNET_SYSERR;
927       }
928       *data_size = off;
929       *data = GNUNET_malloc (off);
930       memcpy (*data, ptrbuf, off);
931       return GNUNET_OK;
932     }
933   case GNUNET_DNSPARSER_TYPE_MX:
934     {
935       struct GNUNET_DNSPARSER_MxRecord mx;
936       char mxbuf[258];
937       char mxhost[253 + 1];
938       uint16_t mx_pref;
939       size_t off;
940
941       if (2 != SSCANF(s, "%hu,%253s", &mx_pref, mxhost))
942       {
943         LOG (GNUNET_ERROR_TYPE_ERROR,
944              _("Unable to parse MX record `%s'\n"),
945              s);
946       return GNUNET_SYSERR;
947       }
948       mx.preference = mx_pref;
949       mx.mxhost = mxhost;
950       off = 0;
951
952       if (GNUNET_OK !=
953           GNUNET_DNSPARSER_builder_add_mx (mxbuf,
954                                            sizeof (mxbuf),
955                                            &off,
956                                            &mx))
957       {
958         LOG (GNUNET_ERROR_TYPE_ERROR,
959              _("Failed to serialize MX record with hostname `%s'\n"),
960              mxhost);
961         return GNUNET_SYSERR;
962       }
963       *data_size = off;
964       *data = GNUNET_malloc (off);
965       memcpy (*data, mxbuf, off);
966       return GNUNET_OK;
967     }
968   case GNUNET_DNSPARSER_TYPE_TXT:
969     *data = GNUNET_strdup (s);
970     *data_size = strlen (s);
971     return GNUNET_OK;
972   case GNUNET_DNSPARSER_TYPE_AAAA:
973     if (1 != inet_pton (AF_INET6, s, &value_aaaa))
974     {
975       LOG (GNUNET_ERROR_TYPE_ERROR,
976            _("Unable to parse IPv6 address `%s'\n"),
977            s);
978       return GNUNET_SYSERR;
979     }
980     *data = GNUNET_malloc (sizeof (struct in6_addr));
981     *data_size = sizeof (struct in6_addr);
982     memcpy (*data, &value_aaaa, sizeof (value_aaaa));
983     return GNUNET_OK;
984   case GNUNET_NAMESTORE_TYPE_PKEY:
985     if (GNUNET_OK !=
986         GNUNET_CRYPTO_ecc_public_sign_key_from_string (s, strlen (s), &pkey))
987     {
988       LOG (GNUNET_ERROR_TYPE_ERROR,
989            _("Unable to parse PKEY record `%s'\n"),
990            s);
991       return GNUNET_SYSERR;
992     }
993     *data = GNUNET_new (struct GNUNET_CRYPTO_EccPublicSignKey);
994     memcpy (*data, &pkey, sizeof (pkey));
995     *data_size = sizeof (struct GNUNET_CRYPTO_EccPublicSignKey);
996     return GNUNET_OK;
997   case GNUNET_NAMESTORE_TYPE_PHONE:
998     {
999       struct GNUNET_CONVERSATION_PhoneRecord *pr;
1000       unsigned int line;
1001       const char *dash;
1002       struct GNUNET_PeerIdentity peer;
1003
1004       if ( (NULL == (dash = strchr (s, '-'))) ||
1005            (1 != sscanf (s, "%u-", &line)) ||
1006            (GNUNET_OK !=
1007             GNUNET_CRYPTO_ecc_public_sign_key_from_string (dash + 1,
1008                                                            strlen (dash + 1),
1009                                                            &peer.public_key)) )
1010       {
1011         LOG (GNUNET_ERROR_TYPE_ERROR,
1012              _("Unable to parse PHONE record `%s'\n"),
1013              s);
1014         return GNUNET_SYSERR;
1015       }
1016       pr = GNUNET_new (struct GNUNET_CONVERSATION_PhoneRecord);
1017       pr->version = htonl (0);
1018       pr->line = htonl ((uint32_t) line);
1019       pr->peer = peer;
1020       *data = pr;
1021       *data_size = sizeof (struct GNUNET_CONVERSATION_PhoneRecord);
1022       return GNUNET_OK;
1023     }
1024   case GNUNET_NAMESTORE_TYPE_PSEU:
1025     *data = GNUNET_strdup (s);
1026     *data_size = strlen (s);
1027     return GNUNET_OK;
1028   case GNUNET_NAMESTORE_TYPE_LEHO:
1029     *data = GNUNET_strdup (s);
1030     *data_size = strlen (s);
1031     return GNUNET_OK;
1032   case GNUNET_NAMESTORE_TYPE_VPN:
1033     if (3 != SSCANF (s,"%u %103s %253s",
1034                      &proto, s_peer, s_serv))
1035     {
1036       LOG (GNUNET_ERROR_TYPE_ERROR,
1037            _("Unable to parse VPN record string `%s'\n"),
1038            s);
1039       return GNUNET_SYSERR;
1040     }
1041     *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
1042     *data = vpn = GNUNET_malloc (*data_size);
1043     if (GNUNET_OK != GNUNET_CRYPTO_ecc_public_sign_key_from_string ((char*) s_peer,
1044                                                                     strlen (s_peer),
1045                                                                     &vpn->peer.public_key))
1046     {
1047       GNUNET_free (vpn);
1048       *data_size = 0;
1049       return GNUNET_SYSERR;
1050     }
1051     vpn->proto = htons ((uint16_t) proto);
1052     strcpy ((char*)&vpn[1], s_serv);
1053     return GNUNET_OK;
1054   case GNUNET_NAMESTORE_TYPE_GNS2DNS:
1055     {
1056       char nsbuf[256];
1057       size_t off;
1058
1059       off = 0;
1060       if (GNUNET_OK !=
1061           GNUNET_DNSPARSER_builder_add_name (nsbuf,
1062                                              sizeof (nsbuf),
1063                                              &off,
1064                                              s))
1065       {
1066         LOG (GNUNET_ERROR_TYPE_ERROR,
1067              _("Failed to serialize GNS2DNS record with value `%s'\n"),
1068              s);
1069         return GNUNET_SYSERR;
1070       }
1071       *data_size = off;
1072       *data = GNUNET_malloc (off);
1073       memcpy (*data, nsbuf, off);
1074       return GNUNET_OK;
1075     }
1076   case GNUNET_DNSPARSER_TYPE_TLSA:
1077     *data_size = sizeof (struct GNUNET_TUN_DnsTlsaRecord) + strlen (s) - 6;
1078     *data = tlsa = GNUNET_malloc (*data_size);
1079     if (4 != SSCANF (s, "%c %c %c %s",
1080                      &tlsa->usage,
1081                      &tlsa->selector,
1082                      &tlsa->matching_type,
1083                      (char*)&tlsa[1]))
1084     {
1085       LOG (GNUNET_ERROR_TYPE_ERROR,
1086            _("Unable to parse TLSA record string `%s'\n"),
1087            s);
1088       *data_size = 0;
1089       GNUNET_free (tlsa);
1090       return GNUNET_SYSERR;
1091     }
1092     return GNUNET_OK;
1093   default:
1094     LOG (GNUNET_ERROR_TYPE_ERROR,
1095          _("Unsupported record type %d\n"),
1096          (int) type);
1097     return GNUNET_SYSERR;
1098   }
1099 }
1100
1101
1102 /**
1103  * Mapping of record type numbers to human-readable
1104  * record type names.
1105  */
1106 static struct {
1107   const char *name;
1108   uint32_t number;
1109 } name_map[] = {
1110   { "A", GNUNET_DNSPARSER_TYPE_A },
1111   { "NS", GNUNET_DNSPARSER_TYPE_NS },
1112   { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
1113   { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
1114   { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
1115   { "MX", GNUNET_DNSPARSER_TYPE_MX },
1116   { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
1117   { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
1118   { "PKEY",  GNUNET_NAMESTORE_TYPE_PKEY },
1119   { "PSEU",  GNUNET_NAMESTORE_TYPE_PSEU },
1120   { "LEHO",  GNUNET_NAMESTORE_TYPE_LEHO },
1121   { "VPN", GNUNET_NAMESTORE_TYPE_VPN },
1122   { "GNS2DNS", GNUNET_NAMESTORE_TYPE_GNS2DNS },
1123   { "PHONE", GNUNET_NAMESTORE_TYPE_PHONE },
1124   { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
1125   { NULL, UINT32_MAX }
1126 };
1127
1128
1129 /**
1130  * Convert a type name (i.e. "AAAA") to the corresponding number.
1131  *
1132  * @param dns_typename name to convert
1133  * @return corresponding number, UINT32_MAX on error
1134  */
1135 uint32_t
1136 GNUNET_NAMESTORE_typename_to_number (const char *dns_typename)
1137 {
1138   unsigned int i;
1139
1140   i=0;
1141   while ( (name_map[i].name != NULL) &&
1142           (0 != strcasecmp (dns_typename, name_map[i].name)) )
1143     i++;
1144   return name_map[i].number;
1145 }
1146
1147
1148 /**
1149  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
1150  *
1151  * @param type number of a type to convert
1152  * @return corresponding typestring, NULL on error
1153  */
1154 const char *
1155 GNUNET_NAMESTORE_number_to_typename (uint32_t type)
1156 {
1157   unsigned int i;
1158
1159   i=0;
1160   while ( (name_map[i].name != NULL) &&
1161           (type != name_map[i].number) )
1162     i++;
1163   return name_map[i].name;
1164 }
1165
1166
1167 /**
1168  * Test if a given record is expired.
1169  *
1170  * @return #GNUNET_YES if the record is expired,
1171  *         #GNUNET_NO if not
1172  */
1173 int
1174 GNUNET_NAMESTORE_is_expired (const struct GNUNET_NAMESTORE_RecordData *rd)
1175 {
1176   struct GNUNET_TIME_Absolute at;
1177
1178   if (0 != (rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
1179     return GNUNET_NO;
1180   at.abs_value_us = rd->expiration_time;
1181   return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value_us) ? GNUNET_YES : GNUNET_NO;
1182 }
1183
1184
1185 /**
1186  * Calculate the DHT query for a given @a label in a given @a zone.
1187  *
1188  * @param zone private key of the zone
1189  * @param label label of the record
1190  * @param query hash to use for the query
1191  */
1192 void
1193 GNUNET_NAMESTORE_query_from_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *zone,
1194                                          const char *label,
1195                                          struct GNUNET_HashCode *query)
1196 {
1197   struct GNUNET_CRYPTO_EccPublicSignKey pub;
1198
1199   GNUNET_CRYPTO_ecc_key_get_public_for_signature (zone, &pub);
1200   GNUNET_NAMESTORE_query_from_public_key (&pub, label, query);
1201 }
1202
1203
1204 /**
1205  * Calculate the DHT query for a given @a label in a given @a zone.
1206  *
1207  * @param pub public key of the zone
1208  * @param label label of the record
1209  * @param query hash to use for the query
1210  */
1211 void
1212 GNUNET_NAMESTORE_query_from_public_key (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
1213                                         const char *label,
1214                                         struct GNUNET_HashCode *query)
1215 {
1216   struct GNUNET_CRYPTO_EccPublicSignKey pd;
1217
1218   GNUNET_CRYPTO_ecc_public_key_derive (pub, label, "gns", &pd);
1219   GNUNET_CRYPTO_hash (&pd, sizeof (pd), query);
1220 }
1221
1222
1223 /**
1224  * Convert public key to the respective absolute domain name in the
1225  * ".zkey" pTLD.
1226  * This is one of the very few calls in the entire API that is
1227  * NOT reentrant!
1228  *
1229  * @param pkey a public key with a point on the eliptic curve
1230  * @return string "X.zkey" where X is the public
1231  *         key in an encoding suitable for DNS labels.
1232  */
1233 const char *
1234 GNUNET_NAMESTORE_pkey_to_zkey (const struct GNUNET_CRYPTO_EccPublicSignKey *pkey)
1235 {
1236   static char ret[128];
1237   char *pkeys;
1238
1239   pkeys = GNUNET_CRYPTO_ecc_public_sign_key_to_string (pkey);
1240   GNUNET_snprintf (ret,
1241                    sizeof (ret),
1242                    "%s.zkey",
1243                    pkeys);
1244   GNUNET_free (pkeys);
1245   return ret;
1246 }
1247
1248
1249 /**
1250  * Convert an absolute domain name in the ".zkey" pTLD to the
1251  * respective public key.
1252  *
1253  * @param zkey string "X.zkey" where X is the coordinates of the public
1254  *         key in an encoding suitable for DNS labels.
1255  * @param pkey set to a public key on the eliptic curve
1256  * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
1257  */
1258 int
1259 GNUNET_NAMESTORE_zkey_to_pkey (const char *zkey,
1260                                struct GNUNET_CRYPTO_EccPublicSignKey *pkey)
1261 {
1262   char *cpy;
1263   char *dot;
1264   const char *x;
1265
1266   cpy = GNUNET_strdup (zkey);
1267   x = cpy;
1268   if (NULL == (dot = strchr (x, (int) '.')))
1269     goto error;
1270   *dot = '\0';
1271   if (0 != strcasecmp (dot + 1,
1272                        "zkey"))
1273     goto error;
1274
1275   if (GNUNET_OK !=
1276       GNUNET_CRYPTO_ecc_public_sign_key_from_string (x,
1277                                                 strlen (x),
1278                                                 pkey))
1279     goto error;
1280   GNUNET_free (cpy);
1281   return GNUNET_OK;
1282  error:
1283   GNUNET_free (cpy);
1284   return GNUNET_SYSERR;
1285 }
1286
1287
1288 /* end of namestore_common.c */