2 This file is part of GNUnet.
3 (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file namestore/namestore_common.c
23 * @brief API to access the NAMESTORE service
24 * @author Martin Schanzenbach
25 * @author Matthias Wachs
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 "gns_protocol.h"
36 #include "namestore.h"
39 #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
41 GNUNET_NETWORK_STRUCT_BEGIN
44 * Internal format of a record in the serialized form.
50 * Expiration time for the DNS record; relative or absolute depends
51 * on 'flags', network byte order.
53 uint64_t expiration_time GNUNET_PACKED;
56 * Number of bytes in 'data', network byte order.
58 uint32_t data_size GNUNET_PACKED;
61 * Type of the GNS/DNS record, network byte order.
63 uint32_t record_type GNUNET_PACKED;
66 * Flags for the record, network byte order.
68 uint32_t flags GNUNET_PACKED;
72 GNUNET_NETWORK_STRUCT_END
75 * Convert a UTF-8 string to UTF-8 lowercase
76 * @param src source string
77 * @return converted result
80 GNUNET_NAMESTORE_normalize_string (const char *src)
82 GNUNET_assert (NULL != src);
83 char *res = strdup (src);
85 GNUNET_STRINGS_utf8_tolower(src, &res);
91 * Convert a short hash to a string (for printing debug messages).
92 * This is one of the very few calls in the entire API that is
95 * @param hc the short hash code
96 * @return string form; will be overwritten by next call to GNUNET_h2s.
99 GNUNET_short_h2s (const struct GNUNET_CRYPTO_ShortHashCode * hc)
101 static struct GNUNET_CRYPTO_ShortHashAsciiEncoded ret;
103 GNUNET_CRYPTO_short_hash_to_enc (hc, &ret);
104 return (const char *) &ret;
109 * Calculate how many bytes we will need to serialize the given
112 * @param rd_count number of records in the rd array
113 * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements
115 * @return the required size to serialize
119 GNUNET_NAMESTORE_records_get_size (unsigned int rd_count,
120 const struct GNUNET_NAMESTORE_RecordData *rd)
125 ret = sizeof (struct NetworkRecord) * rd_count;
126 for (i=0;i<rd_count;i++)
128 GNUNET_assert ((ret + rd[i].data_size) >= ret);
129 ret += rd[i].data_size;
136 * Serialize the given records to the given destination buffer.
138 * @param rd_count number of records in the rd array
139 * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements
140 * @param dest_size size of the destination array
141 * @param dest where to write the result
143 * @return the size of serialized records, -1 if records do not fit
146 GNUNET_NAMESTORE_records_serialize (unsigned int rd_count,
147 const struct GNUNET_NAMESTORE_RecordData *rd,
151 struct NetworkRecord rec;
156 for (i=0;i<rd_count;i++)
158 rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
159 rec.data_size = htonl ((uint32_t) rd[i].data_size);
160 rec.record_type = htonl (rd[i].record_type);
161 rec.flags = htonl (rd[i].flags);
162 if (off + sizeof (rec) > dest_size)
164 memcpy (&dest[off], &rec, sizeof (rec));
166 if (off + rd[i].data_size > dest_size)
168 memcpy (&dest[off], rd[i].data, rd[i].data_size);
169 off += rd[i].data_size;
176 * Compares if two records are equal (ignoring flags such
177 * as authority, private and pending, but not relative vs.
178 * absolute expiration time).
182 * @return GNUNET_YES if the records are equal or GNUNET_NO if they are not
185 GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a,
186 const struct GNUNET_NAMESTORE_RecordData *b)
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 "Comparing records\n");
190 if (a->record_type != b->record_type)
192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 "Record type %lu != %lu\n", a->record_type, b->record_type);
196 if ((a->expiration_time != b->expiration_time) &&
197 ((a->expiration_time != 0) && (b->expiration_time != 0)))
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Expiration time %llu != %llu\n", a->expiration_time, b->expiration_time);
203 if ((a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS)
204 != (b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS))
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
208 a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS, b->flags,
209 b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS);
212 if (a->data_size != b->data_size)
214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
215 "Data size %lu != %lu\n", a->data_size, b->data_size);
218 if (0 != memcmp (a->data, b->data, a->data_size))
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
221 "Data contents do not match\n");
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Records are equal\n");
231 * Deserialize the given records to the given destination.
233 * @param len size of the serialized record data
234 * @param src the serialized record data
235 * @param rd_count number of records in the rd array
236 * @param dest where to put the data
238 * @return GNUNET_OK on success, GNUNET_SYSERR on error
241 GNUNET_NAMESTORE_records_deserialize (size_t len,
243 unsigned int rd_count,
244 struct GNUNET_NAMESTORE_RecordData *dest)
246 struct NetworkRecord rec;
251 for (i=0;i<rd_count;i++)
253 if (off + sizeof (rec) > len)
254 return GNUNET_SYSERR;
255 memcpy (&rec, &src[off], sizeof (rec));
256 dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
257 dest[i].data_size = ntohl ((uint32_t) rec.data_size);
258 dest[i].record_type = ntohl (rec.record_type);
259 dest[i].flags = ntohl (rec.flags);
262 if (off + dest[i].data_size > len)
263 return GNUNET_SYSERR;
264 dest[i].data = &src[off];
265 off += dest[i].data_size;
272 * Sign name and records
274 * @param key the private key
275 * @param expire block expiration
276 * @param name the name
277 * @param rd record data
278 * @param rd_count number of records
280 * @return the signature
282 struct GNUNET_CRYPTO_RsaSignature *
283 GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
284 struct GNUNET_TIME_Absolute expire,
286 const struct GNUNET_NAMESTORE_RecordData *rd,
287 unsigned int rd_count)
289 struct GNUNET_CRYPTO_RsaSignature *sig;
290 struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose;
291 struct GNUNET_TIME_AbsoluteNBO expire_nbo;
294 struct GNUNET_TIME_AbsoluteNBO *expire_tmp;
305 sig = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaSignature));
306 name_len = strlen (name) + 1;
307 expire_nbo = GNUNET_TIME_absolute_hton (expire);
308 rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
310 char rd_ser[rd_ser_len];
312 GNUNET_assert (rd_ser_len ==
313 GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser));
314 sig_len = sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len;
315 sig_purpose = GNUNET_malloc (sig_len);
316 sig_purpose->size = htonl (sig_len);
317 sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
318 expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1];
319 memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO));
320 name_tmp = (char *) &expire_tmp[1];
321 memcpy (name_tmp, name, name_len);
322 rd_tmp = &name_tmp[name_len];
323 memcpy (rd_tmp, rd_ser, rd_ser_len);
324 res = GNUNET_CRYPTO_rsa_sign (key, sig_purpose, sig);
325 GNUNET_free (sig_purpose);
327 if (GNUNET_OK != res)
338 * Convert the 'value' of a record to a string.
340 * @param type type of the record
341 * @param data value in binary encoding
342 * @param data_size number of bytes in data
343 * @return NULL on error, otherwise human-readable representation of the value
346 GNUNET_NAMESTORE_value_to_string (uint32_t type,
351 const struct soa_data *soa;
352 const struct vpn_data *vpn;
353 const struct srv_data *srv;
354 const struct tlsa_data *tlsa;
355 struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
356 struct GNUNET_CRYPTO_HashAsciiEncoded s_peer;
362 const char* soa_rname;
363 const char* soa_mname;
364 char tmp[INET6_ADDRSTRLEN];
370 case GNUNET_DNSPARSER_TYPE_A:
371 if (data_size != sizeof (struct in_addr))
373 if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
375 return GNUNET_strdup (tmp);
376 case GNUNET_DNSPARSER_TYPE_NS:
377 return GNUNET_strndup (data, data_size);
378 case GNUNET_DNSPARSER_TYPE_CNAME:
379 return GNUNET_strndup (data, data_size);
380 case GNUNET_DNSPARSER_TYPE_SOA:
381 if (data_size <= sizeof (struct soa_data))
384 soa_rname = (const char*) &soa[1];
385 soa_mname = memchr (soa_rname, 0, data_size - sizeof (struct soa_data) - 1);
386 if (NULL == soa_mname)
389 if (NULL == memchr (soa_mname, 0,
390 data_size - (sizeof (struct soa_data) + strlen (soa_rname) + 1)))
392 GNUNET_asprintf (&result,
393 "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
394 soa_rname, soa_mname,
396 ntohl (soa->refresh),
399 ntohl (soa->minimum));
401 case GNUNET_DNSPARSER_TYPE_PTR:
402 return GNUNET_strndup (data, data_size);
403 case GNUNET_DNSPARSER_TYPE_MX:
404 mx_pref = ntohs(*((uint16_t*)data));
405 if (GNUNET_asprintf(&result, "%hu,%s", mx_pref, data+sizeof(uint16_t))
410 GNUNET_free (result);
413 case GNUNET_DNSPARSER_TYPE_TXT:
414 return GNUNET_strndup (data, data_size);
415 case GNUNET_DNSPARSER_TYPE_AAAA:
416 if (data_size != sizeof (struct in6_addr))
418 if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
420 return GNUNET_strdup (tmp);
421 case GNUNET_NAMESTORE_TYPE_PKEY:
422 if (data_size != sizeof (struct GNUNET_CRYPTO_ShortHashCode))
424 GNUNET_CRYPTO_short_hash_to_enc (data,
426 return GNUNET_strdup ((const char*) enc.short_encoding);
427 case GNUNET_NAMESTORE_TYPE_PSEU:
428 return GNUNET_strndup (data, data_size);
429 case GNUNET_NAMESTORE_TYPE_LEHO:
430 return GNUNET_strndup (data, data_size);
431 case GNUNET_NAMESTORE_TYPE_VPN:
433 if ( (data_size <= sizeof (struct vpn_data)) ||
434 ('\0' != cdata[data_size - 1]) )
435 return NULL; /* malformed */
437 GNUNET_CRYPTO_hash_to_enc (&vpn->peer, &s_peer);
438 if (0 == GNUNET_asprintf (&vpn_str, "%u %s %s",
439 (unsigned int) ntohs (vpn->proto),
440 (const char*) &s_peer,
441 (const char*) &vpn[1]))
443 GNUNET_free (vpn_str);
447 case GNUNET_DNSPARSER_TYPE_SRV:
449 if ( (data_size <= sizeof (struct srv_data)) ||
450 ('\0' != cdata[data_size - 1]) )
451 return NULL; /* malformed */
454 if (0 == GNUNET_asprintf (&srv_str,
459 (const char *)&srv[1]))
461 GNUNET_free (srv_str);
465 case GNUNET_DNSPARSER_TYPE_TLSA:
467 if ( (data_size <= sizeof (struct tlsa_data)) ||
468 ('\0' != cdata[data_size - 1]) )
469 return NULL; /* malformed */
471 if (0 == GNUNET_asprintf (&tlsa_str,
476 (const char *) &tlsa[1]))
478 GNUNET_free (tlsa_str);
485 GNUNET_break (0); // not implemented
491 * Convert human-readable version of a 'value' of a record to the binary
494 * @param type type of the record
495 * @param s human-readable string
496 * @param data set to value in binary encoding (will be allocated)
497 * @param data_size set to number of bytes in data
498 * @return GNUNET_OK on success
501 GNUNET_NAMESTORE_string_to_value (uint32_t type,
506 struct in_addr value_a;
507 struct in6_addr value_aaaa;
508 struct GNUNET_CRYPTO_ShortHashCode pkey;
509 struct soa_data *soa;
510 struct vpn_data *vpn;
511 struct tlsa_data *tlsa;
512 char result[253 + 1];
513 char soa_rname[253 + 1];
514 char soa_mname[253 + 1];
515 char s_peer[103 + 1];
516 char s_serv[253 + 1];
517 unsigned int soa_serial;
518 unsigned int soa_refresh;
519 unsigned int soa_retry;
520 unsigned int soa_expire;
521 unsigned int soa_min;
529 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
530 _("Unsupported record type %d\n"),
532 return GNUNET_SYSERR;
533 case GNUNET_DNSPARSER_TYPE_A:
534 if (1 != inet_pton (AF_INET, s, &value_a))
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 _("Unable to parse IPv4 address `%s'\n"),
539 return GNUNET_SYSERR;
541 *data = GNUNET_malloc (sizeof (struct in_addr));
542 memcpy (*data, &value_a, sizeof (value_a));
543 *data_size = sizeof (value_a);
545 case GNUNET_DNSPARSER_TYPE_NS:
546 *data = GNUNET_strdup (s);
547 *data_size = strlen (s) + 1;
549 case GNUNET_DNSPARSER_TYPE_CNAME:
550 *data = GNUNET_strdup (s);
551 *data_size = strlen (s) + 1;
553 case GNUNET_DNSPARSER_TYPE_SOA:
555 "rname=%253s mname=%253s %u,%u,%u,%u,%u",
556 soa_rname, soa_mname,
557 &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min))
559 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
560 _("Unable to parse SOA record `%s'\n"),
562 return GNUNET_SYSERR;
564 *data_size = sizeof (struct soa_data)+strlen(soa_rname)+strlen(soa_mname)+2;
565 *data = GNUNET_malloc (*data_size);
566 soa = (struct soa_data*)*data;
567 soa->serial = htonl(soa_serial);
568 soa->refresh = htonl(soa_refresh);
569 soa->retry = htonl(soa_retry);
570 soa->expire = htonl(soa_expire);
571 soa->minimum = htonl(soa_min);
572 strcpy((char*)&soa[1], soa_rname);
573 strcpy((char*)&soa[1]+strlen(*data)+1, soa_mname);
575 case GNUNET_DNSPARSER_TYPE_PTR:
576 *data = GNUNET_strdup (s);
577 *data_size = strlen (s);
579 case GNUNET_DNSPARSER_TYPE_MX:
580 if (2 != SSCANF(s, "%hu,%253s", &mx_pref, result))
582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583 _("Unable to parse MX record `%s'\n"),
585 return GNUNET_SYSERR;
587 *data_size = sizeof (uint16_t)+strlen(result)+1;
588 *data = GNUNET_malloc (*data_size);
589 mx_pref_n = htons(mx_pref);
590 memcpy(*data, &mx_pref_n, sizeof (uint16_t));
591 strcpy((*data)+sizeof (uint16_t), result);
593 case GNUNET_DNSPARSER_TYPE_TXT:
594 *data = GNUNET_strdup (s);
595 *data_size = strlen (s);
597 case GNUNET_DNSPARSER_TYPE_AAAA:
598 if (1 != inet_pton (AF_INET6, s, &value_aaaa))
600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601 _("Unable to parse IPv6 address `%s'\n"),
603 return GNUNET_SYSERR;
605 *data = GNUNET_malloc (sizeof (struct in6_addr));
606 *data_size = sizeof (struct in6_addr);
607 memcpy (*data, &value_aaaa, sizeof (value_aaaa));
609 case GNUNET_NAMESTORE_TYPE_PKEY:
611 GNUNET_CRYPTO_short_hash_from_string (s, &pkey))
613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
614 _("Unable to parse PKEY record `%s'\n"),
616 return GNUNET_SYSERR;
618 *data = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode));
619 memcpy (*data, &pkey, sizeof (pkey));
620 *data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
622 case GNUNET_NAMESTORE_TYPE_PSEU:
623 *data = GNUNET_strdup (s);
624 *data_size = strlen (s);
626 case GNUNET_NAMESTORE_TYPE_LEHO:
627 *data = GNUNET_strdup (s);
628 *data_size = strlen (s);
630 case GNUNET_NAMESTORE_TYPE_VPN:
631 if (3 != SSCANF (s,"%u %103s %253s",
632 &proto, s_peer, s_serv))
634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
635 _("Unable to parse VPN record string `%s'\n"),
637 return GNUNET_SYSERR;
639 *data_size = sizeof (struct vpn_data) + strlen (s_serv) + 1;
640 *data = vpn = GNUNET_malloc (*data_size);
641 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_peer,
646 return GNUNET_SYSERR;
648 vpn->proto = htons ((uint16_t) proto);
649 strcpy ((char*)&vpn[1], s_serv);
651 case GNUNET_DNSPARSER_TYPE_TLSA:
652 *data_size = sizeof (struct tlsa_data) + strlen (s) - 6;
653 *data = tlsa = GNUNET_malloc (*data_size);
654 if (4 != SSCANF (s, "%c %c %c %s",
657 &tlsa->matching_type,
660 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
661 _("Unable to parse TLSA record string `%s'\n"),
665 return GNUNET_SYSERR;
669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
670 _("Unsupported record type %d\n"),
672 return GNUNET_SYSERR;
681 { "A", GNUNET_DNSPARSER_TYPE_A },
682 { "NS", GNUNET_DNSPARSER_TYPE_NS },
683 { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
684 { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
685 { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
686 { "MX", GNUNET_DNSPARSER_TYPE_MX },
687 { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
688 { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
689 { "PKEY", GNUNET_NAMESTORE_TYPE_PKEY },
690 { "PSEU", GNUNET_NAMESTORE_TYPE_PSEU },
691 { "LEHO", GNUNET_NAMESTORE_TYPE_LEHO },
692 { "VPN", GNUNET_NAMESTORE_TYPE_VPN },
693 { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
699 * Convert a type name (i.e. "AAAA") to the corresponding number.
701 * @param typename name to convert
702 * @return corresponding number, UINT32_MAX on error
705 GNUNET_NAMESTORE_typename_to_number (const char *typename)
710 while ( (name_map[i].name != NULL) &&
711 (0 != strcasecmp (typename, name_map[i].name)) )
713 return name_map[i].number;
718 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
720 * @param type number of a type to convert
721 * @return corresponding typestring, NULL on error
724 GNUNET_NAMESTORE_number_to_typename (uint32_t type)
729 while ( (name_map[i].name != NULL) &&
730 (type != name_map[i].number) )
732 return name_map[i].name;
736 * Test if a given record is expired.
738 * @return GNUNET_YES if the record is expired,
742 GNUNET_NAMESTORE_is_expired (const struct GNUNET_NAMESTORE_RecordData *rd)
744 struct GNUNET_TIME_Absolute at;
746 if (0 != (rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
748 at.abs_value = rd->expiration_time;
749 return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value) ? GNUNET_YES : GNUNET_NO;
753 /* end of namestore_common.c */