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