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