aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2022-02-07 15:59:04 +0100
committerMartin Schanzenbach <schanzen@gnunet.org>2022-02-07 15:59:04 +0100
commit14b3c75ab523830f5c1744d5a0faa4168b4172a7 (patch)
treeeecc64f41891b29f5c1edd42f9315a2ab2733c59
parent1c89bfe03f45eef178a1e5a5d4d33057946ebf11 (diff)
downloadgnunet-14b3c75ab523830f5c1744d5a0faa4168b4172a7.tar.gz
gnunet-14b3c75ab523830f5c1744d5a0faa4168b4172a7.zip
GNS: LSD0001 improvements
NAMESTORE: Better error handling. Fixed private record feature. GNSRECORD: Record inconsistency check for delegation and redirection records
-rw-r--r--src/gnsrecord/gnsrecord_misc.c137
-rw-r--r--src/include/gnunet_gns_service.h6
-rw-r--r--src/include/gnunet_gnsrecord_lib.h61
-rw-r--r--src/namestore/gnunet-service-namestore.c103
-rw-r--r--src/namestore/namestore.h14
-rw-r--r--src/namestore/namestore_api.c46
-rw-r--r--src/zonemaster/gnunet-service-zonemaster-monitor.c20
-rw-r--r--src/zonemaster/gnunet-service-zonemaster.c20
8 files changed, 317 insertions, 90 deletions
diff --git a/src/gnsrecord/gnsrecord_misc.c b/src/gnsrecord/gnsrecord_misc.c
index 5c20dbedc..5bf4aa371 100644
--- a/src/gnsrecord/gnsrecord_misc.c
+++ b/src/gnsrecord/gnsrecord_misc.c
@@ -300,7 +300,8 @@ GNUNET_GNSRECORD_data_from_identity (const struct
300 return GNUNET_SYSERR; 300 return GNUNET_SYSERR;
301 tmp = GNUNET_malloc (*data_size); 301 tmp = GNUNET_malloc (*data_size);
302 if (GNUNET_IDENTITY_write_key_to_buffer (key, tmp, *data_size) 302 if (GNUNET_IDENTITY_write_key_to_buffer (key, tmp, *data_size)
303 != *data_size) { 303 != *data_size)
304 {
304 GNUNET_free (tmp); 305 GNUNET_free (tmp);
305 *data_size = 0; 306 *data_size = 0;
306 return GNUNET_SYSERR; 307 return GNUNET_SYSERR;
@@ -399,44 +400,148 @@ GNUNET_GNSRECORD_record_to_identity_key (const struct GNUNET_GNSRECORD_Data *rd,
399 400
400} 401}
401 402
402unsigned int 403enum GNUNET_GenericReturnValue
403GNUNET_GNSRECORD_convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, 404GNUNET_GNSRECORD_normalize_record_set (const char *label,
404 unsigned int rd_count, 405 const struct
405 struct GNUNET_GNSRECORD_Data *rd_public, 406 GNUNET_GNSRECORD_Data *rd,
406 struct GNUNET_TIME_Absolute *expiry) 407 unsigned int rd_count,
408 struct GNUNET_GNSRECORD_Data *
409 rd_public,
410 unsigned int *rd_count_public,
411 struct GNUNET_TIME_Absolute *expiry,
412 int include_private,
413 char **emsg)
407{ 414{
408 struct GNUNET_TIME_Absolute expiry_tombstone; 415 struct GNUNET_TIME_Absolute expiry_tombstone;
409 struct GNUNET_TIME_Absolute now; 416 struct GNUNET_TIME_Absolute now;
410 struct GNUNET_TIME_Absolute minimum_expiration; 417 struct GNUNET_TIME_Absolute minimum_expiration;
411 unsigned int rd_public_count; 418 int have_zone_delegation = GNUNET_NO;
419 int have_gns2dns = GNUNET_NO;
420 int have_other = GNUNET_NO;
421 int have_redirect = GNUNET_NO;
422 int have_empty_label = (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, label));
423 unsigned int rd_count_tmp;
412 424
413 rd_public_count = 0;
414 minimum_expiration = GNUNET_TIME_UNIT_FOREVER_ABS; 425 minimum_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
415 now = GNUNET_TIME_absolute_get (); 426 now = GNUNET_TIME_absolute_get ();
427 rd_count_tmp = 0;
416 for (unsigned int i = 0; i < rd_count; i++) 428 for (unsigned int i = 0; i < rd_count; i++)
417 { 429 {
430 /* Ignore the tombstone. For maintenance only. Remember expiration time. */
418 if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type) 431 if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type)
419 { 432 {
420 minimum_expiration.abs_value_us = rd[i].expiration_time; 433 minimum_expiration.abs_value_us = rd[i].expiration_time;
421 continue; 434 continue;
422 } 435 }
423 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) 436 /* No NICK records unless empty label */
437 if (have_empty_label &&
438 (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type))
439 continue;
440
441 /**
442 * Check for delegation and redirect consistency.
443 * Note that we check for consistency BEFORE we filter for
444 * private records ON PURPOSE.
445 * We also want consistent record sets in our local zone(s).
446 * The only exception is the tombstone (above) which we ignore
447 * for the consistency check(s).
448 */
449 if (GNUNET_YES == GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type))
450 {
451 have_zone_delegation = GNUNET_YES;
452 /* No delegation records under empty label*/
453 if (have_empty_label)
454 {
455 *emsg = GNUNET_strdup (_ (
456 "Record set inconsistent: Multiple delegation records."));
457 return GNUNET_SYSERR;
458 }
459 }
460 else if (GNUNET_GNSRECORD_TYPE_REDIRECT == rd[i].record_type)
461 {
462 if (GNUNET_YES == have_redirect)
463 {
464 *emsg = GNUNET_strdup (_ (
465 "Record set inconsistent: Multiple REDIRECT records."));
466 return GNUNET_SYSERR;
467 }
468 have_redirect = GNUNET_YES;
469 /* No redirection records under empty label*/
470 if (have_empty_label)
471 {
472 *emsg = GNUNET_strdup (_ (
473 "Record set inconsistent: REDIRECT record under apex label."));
474 return GNUNET_SYSERR;
475 }
476 }
477 else if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rd[i].record_type)
478 {
479 have_gns2dns = GNUNET_YES;
480 /* No gns2dns records under empty label*/
481 if (have_empty_label)
482 {
483 *emsg = GNUNET_strdup (_ (
484 "Record set inconsistent: GNS2DNS record under apex label.\n"));
485 return GNUNET_SYSERR;
486 }
487 }
488 else
489 {
490 /* Some other record.
491 * Not allowed for zone delegations or redirections */
492 if ((GNUNET_YES == have_zone_delegation) ||
493 (GNUNET_YES == have_redirect) ||
494 (GNUNET_YES == have_gns2dns))
495 {
496 *emsg = GNUNET_strdup (_("Record set inconsistent: Mutually exclusive records.\n"));
497 return GNUNET_SYSERR;
498 have_other = GNUNET_YES;
499 }
500 }
501
502 /* Ignore private records for public record set */
503
504 if ((GNUNET_NO != include_private) &&
505 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)))
424 continue; 506 continue;
507 /* Skip expired records */
425 if ((0 == (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) && 508 if ((0 == (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) &&
426 (rd[i].expiration_time < now.abs_value_us)) 509 (rd[i].expiration_time < now.abs_value_us))
427 continue; /* record already expired, skip it */ 510 continue; /* record already expired, skip it */
428 rd_public[rd_public_count] = rd[i]; 511 rd_public[rd_count_tmp] = rd[i];
429 /* Make sure critical record types are published as such */ 512 /* Make sure critical record types are marked as such */
430 if (GNUNET_YES == GNUNET_GNSRECORD_is_critical (rd[i].record_type)) 513 if (GNUNET_YES == GNUNET_GNSRECORD_is_critical (rd[i].record_type))
431 rd_public[rd_public_count].flags |= GNUNET_GNSRECORD_RF_CRITICAL; 514 rd_public[rd_count_tmp].flags |= GNUNET_GNSRECORD_RF_CRITICAL;
432 rd_public_count++; 515 rd_count_tmp++;
433 } 516 }
434 517
435 *expiry = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count, 518 *expiry = GNUNET_GNSRECORD_record_get_expiration_time (rd_count_tmp,
436 rd_public, 519 rd_public,
437 minimum_expiration); 520 minimum_expiration);
521 *rd_count_public = rd_count_tmp;
522 return GNUNET_OK;
523}
524
525enum GNUNET_GenericReturnValue
526GNUNET_GNSRECORD_convert_records_for_export (const char *label,
527 const struct
528 GNUNET_GNSRECORD_Data *rd,
529 unsigned int rd_count,
530 struct GNUNET_GNSRECORD_Data *
531 rd_public,
532 unsigned int *rd_count_public,
533 struct GNUNET_TIME_Absolute *expiry,
534 char **emsg)
535{
536 return GNUNET_GNSRECORD_normalize_record_set (label,
537 rd,
538 rd_count,
539 rd_public,
540 rd_count_public,
541 expiry,
542 GNUNET_NO,
543 emsg);
438 544
439 return rd_public_count;
440} 545}
441 546
442 547
diff --git a/src/include/gnunet_gns_service.h b/src/include/gnunet_gns_service.h
index 3f6c9b9aa..5c06f8045 100644
--- a/src/include/gnunet_gns_service.h
+++ b/src/include/gnunet_gns_service.h
@@ -48,12 +48,6 @@ extern "C" {
48 48
49 49
50/** 50/**
51 * String we use to indicate an empty label (top-level
52 * entry in the zone). DNS uses "@", so do we.
53 */
54#define GNUNET_GNS_EMPTY_LABEL_AT "@"
55
56/**
57 * Connection to the GNS service. 51 * Connection to the GNS service.
58 */ 52 */
59struct GNUNET_GNS_Handle; 53struct GNUNET_GNS_Handle;
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h
index c376b1d1f..cbf7ee15c 100644
--- a/src/include/gnunet_gnsrecord_lib.h
+++ b/src/include/gnunet_gnsrecord_lib.h
@@ -44,6 +44,12 @@ extern "C" {
44#endif 44#endif
45 45
46/** 46/**
47 * String we use to indicate an empty label (top-level
48 * entry in the zone). DNS uses "@", so do we.
49 */
50#define GNUNET_GNS_EMPTY_LABEL_AT "@"
51
52/**
47 * Maximum size of a value that can be stored in a GNS block. 53 * Maximum size of a value that can be stored in a GNS block.
48 */ 54 */
49#define GNUNET_GNSRECORD_MAX_BLOCK_SIZE (63 * 1024) 55#define GNUNET_GNSRECORD_MAX_BLOCK_SIZE (63 * 1024)
@@ -619,7 +625,8 @@ GNUNET_GNSRECORD_records_cmp (const struct GNUNET_GNSRECORD_Data *a,
619 */ 625 */
620struct GNUNET_TIME_Absolute 626struct GNUNET_TIME_Absolute
621GNUNET_GNSRECORD_record_get_expiration_time (unsigned int rd_count, 627GNUNET_GNSRECORD_record_get_expiration_time (unsigned int rd_count,
622 const struct GNUNET_GNSRECORD_Data *rd, 628 const struct
629 GNUNET_GNSRECORD_Data *rd,
623 struct GNUNET_TIME_Absolute min); 630 struct GNUNET_TIME_Absolute min);
624 631
625 632
@@ -710,21 +717,57 @@ enum GNUNET_GenericReturnValue
710GNUNET_GNSRECORD_is_critical (uint32_t type); 717GNUNET_GNSRECORD_is_critical (uint32_t type);
711 718
712/** 719/**
720 * Normalize namestore records: Check for consistency and
721 * expirations. Purge expired records. Returns a "clean" record set.
722 * Also returns the minimum expiration time this block should be
723 * published under.
724 * Also checks rules with respect to labels (e.g. no delegations under
725 * the empty label)
726 *
727 * @param label the label under which this set (supposed to be) stored.
728 * @param rd input records
729 * @param rd_count size of the @a rd and @a rd_public arrays
730 * @param rd_public where to write the converted records
731 * @param rd_public_count number of records written to @a rd_public
732 * @param min_expiry the minimum expiration of this set
733 * @param include_private GNUNET_YES if private records should be included.
734 * @param emsg the error message if something went wrong
735 * @return GNUNET_OK if set could be normalized and is consistent
736 */
737enum GNUNET_GenericReturnValue
738GNUNET_GNSRECORD_normalize_record_set (const char *label,
739 const struct GNUNET_GNSRECORD_Data *rd,
740 unsigned int rd_count,
741 struct GNUNET_GNSRECORD_Data *rd_public,
742 unsigned int *rd_count_public,
743 struct GNUNET_TIME_Absolute *min_expiry,
744 int include_private,
745 char **emsg);
746
747
748/**
713 * Convert namestore records from the internal format to that 749 * Convert namestore records from the internal format to that
714 * suitable for publication (removes private records, converts 750 * suitable for publication (removes private records).
715 * to absolute expiration time).
716 * 751 *
752 * @param label the label under which this set is (supposed to be) published.
717 * @param rd input records 753 * @param rd input records
718 * @param rd_count size of the @a rd and @a rd_public arrays 754 * @param rd_count size of the @a rd and @a rd_public arrays
719 * @param rd_public where to write the converted records 755 * @param rd_public where to write the converted records
756 * @param rd_public_count number of records written to @a rd_public
720 * @param expiry the expiration of the block 757 * @param expiry the expiration of the block
721 * @return number of records written to @a rd_public 758 * @param emsg the error message if something went wrong
759 * @return GNUNET_OK if set is consistent and can be exported
722 */ 760 */
723unsigned int 761enum GNUNET_GenericReturnValue
724GNUNET_GNSRECORD_convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, 762GNUNET_GNSRECORD_convert_records_for_export (const char *label,
725 unsigned int rd_count, 763 const struct
726 struct GNUNET_GNSRECORD_Data *rd_public, 764 GNUNET_GNSRECORD_Data *rd,
727 struct GNUNET_TIME_Absolute *expiry); 765 unsigned int rd_count,
766 struct GNUNET_GNSRECORD_Data *
767 rd_public,
768 unsigned int *rd_count_public,
769 struct GNUNET_TIME_Absolute *expiry,
770 char **emsg);
728 771
729#if 0 /* keep Emacsens' auto-indent happy */ 772#if 0 /* keep Emacsens' auto-indent happy */
730{ 773{
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c
index acf49de9e..51f9b9168 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -808,7 +808,8 @@ send_lookup_response (struct NamestoreClient *nc,
808 * @param rid client's request ID 808 * @param rid client's request ID
809 */ 809 */
810static void 810static void
811send_store_response (struct NamestoreClient *nc, int res, uint32_t rid) 811send_store_response (struct NamestoreClient *nc, int res, const char*emsg,
812 uint32_t rid)
812{ 813{
813 struct GNUNET_MQ_Envelope *env; 814 struct GNUNET_MQ_Envelope *env;
814 struct RecordStoreResponseMessage *rcr_msg; 815 struct RecordStoreResponseMessage *rcr_msg;
@@ -820,10 +821,17 @@ send_store_response (struct NamestoreClient *nc, int res, uint32_t rid)
820 "Store requests completed", 821 "Store requests completed",
821 1, 822 1,
822 GNUNET_NO); 823 GNUNET_NO);
823 env = GNUNET_MQ_msg (rcr_msg, 824 env = GNUNET_MQ_msg_extra (rcr_msg,
824 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE); 825 (NULL != emsg) ? strlen (emsg) + 1 : 0,
826 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE);
825 rcr_msg->gns_header.r_id = htonl (rid); 827 rcr_msg->gns_header.r_id = htonl (rid);
826 rcr_msg->op_result = htonl (res); 828 rcr_msg->op_result = htonl (res);
829 rcr_msg->reserved = htons (0);
830 if (NULL != emsg)
831 {
832 rcr_msg->emsg_len = htons (strlen (emsg) + 1);
833 memcpy (&rcr_msg[1], emsg, strlen (emsg) + 1);
834 }
827 GNUNET_MQ_send (nc->mq, env); 835 GNUNET_MQ_send (nc->mq, env);
828} 836}
829 837
@@ -874,7 +882,7 @@ finish_cache_operation (void *cls, int32_t success, const char *emsg)
874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CACHE operation completed\n"); 882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CACHE operation completed\n");
875 GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); 883 GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop);
876 if (NULL != cop->nc) 884 if (NULL != cop->nc)
877 send_store_response (cop->nc, success, cop->rid); 885 send_store_response (cop->nc, success, emsg, cop->rid);
878 if (NULL != (zi = cop->zi)) 886 if (NULL != (zi = cop->zi))
879 { 887 {
880 zi->cache_ops--; 888 zi->cache_ops--;
@@ -931,7 +939,7 @@ refresh_block (struct NamestoreClient *nc,
931 if (0 == res_count) 939 if (0 == res_count)
932 { 940 {
933 if (NULL != nc) 941 if (NULL != nc)
934 send_store_response (nc, GNUNET_OK, rid); 942 send_store_response (nc, GNUNET_OK, NULL, rid);
935 if (rd != res) 943 if (rd != res)
936 GNUNET_free (res); 944 GNUNET_free (res);
937 return; /* no data, no need to update cache */ 945 return; /* no data, no need to update cache */
@@ -943,7 +951,7 @@ refresh_block (struct NamestoreClient *nc,
943 1, 951 1,
944 GNUNET_NO); 952 GNUNET_NO);
945 if (NULL != nc) 953 if (NULL != nc)
946 send_store_response (nc, GNUNET_OK, rid); 954 send_store_response (nc, GNUNET_OK, NULL, rid);
947 if (rd != res) 955 if (rd != res)
948 GNUNET_free (res); 956 GNUNET_free (res);
949 return; 957 return;
@@ -1472,11 +1480,21 @@ get_block_exp_existing (void *cls,
1472{ 1480{
1473 struct GNUNET_TIME_Absolute *exp = cls; 1481 struct GNUNET_TIME_Absolute *exp = cls;
1474 struct GNUNET_GNSRECORD_Data rd_pub[rd_count]; 1482 struct GNUNET_GNSRECORD_Data rd_pub[rd_count];
1483 unsigned int rd_pub_count;
1484 char *emsg;
1475 1485
1476 GNUNET_GNSRECORD_convert_records_for_export (rd, 1486 if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label,
1487 rd,
1477 rd_count, 1488 rd_count,
1478 rd_pub, 1489 rd_pub,
1479 exp); 1490 &rd_pub_count,
1491 exp,
1492 &emsg))
1493 {
1494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1495 "%s\n", emsg);
1496 GNUNET_free (emsg);
1497 }
1480} 1498}
1481 1499
1482 1500
@@ -1501,12 +1519,10 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1501 struct StoreActivity *sa; 1519 struct StoreActivity *sa;
1502 struct GNUNET_TIME_Absolute existing_block_exp; 1520 struct GNUNET_TIME_Absolute existing_block_exp;
1503 struct GNUNET_TIME_Absolute new_block_exp; 1521 struct GNUNET_TIME_Absolute new_block_exp;
1504 struct GNUNET_GNSRECORD_Data *tombstone_record;
1505 1522
1506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1507 "Received NAMESTORE_RECORD_STORE message\n"); 1524 "Received NAMESTORE_RECORD_STORE message\n");
1508 existing_block_exp.abs_value_us = 0; 1525 existing_block_exp.abs_value_us = 0;
1509 tombstone_record = NULL;
1510 rid = ntohl (rp_msg->gns_header.r_id); 1526 rid = ntohl (rp_msg->gns_header.r_id);
1511 name_len = ntohs (rp_msg->name_len); 1527 name_len = ntohs (rp_msg->name_len);
1512 rd_count = ntohs (rp_msg->rd_count); 1528 rd_count = ntohs (rp_msg->rd_count);
@@ -1560,21 +1576,23 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1560 /* remove "NICK" records, unless this is for the 1576 /* remove "NICK" records, unless this is for the
1561 #GNUNET_GNS_EMPTY_LABEL_AT label 1577 #GNUNET_GNS_EMPTY_LABEL_AT label
1562 We may need one additional record later for tombstone. 1578 We may need one additional record later for tombstone.
1579 FIXME: Since we must normalize the record set (check for
1580 consistency etc) we have to iterate the set twice.
1581 May be inefficient.
1582 We cannot really move the nick caching into GNSRECORD.
1563 */ 1583 */
1564 struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count) + 1]; 1584 struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)];
1585 struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1];
1565 unsigned int rd_clean_off; 1586 unsigned int rd_clean_off;
1587 unsigned int rd_nf_count;
1588 char *emsg;
1566 int have_nick; 1589 int have_nick;
1567 1590
1568 rd_clean_off = 0; 1591 rd_clean_off = 0;
1569 have_nick = GNUNET_NO; 1592 have_nick = GNUNET_NO;
1570 for (unsigned int i = 0; i < rd_count; i++) 1593 for (unsigned int i = 0; i < rd_count; i++)
1571 { 1594 {
1572 /* Do not allow to set tombstone records unless zonemaster */
1573 rd_clean[rd_clean_off] = rd[i]; 1595 rd_clean[rd_clean_off] = rd[i];
1574 if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type)
1575 tombstone_record = &rd_clean[rd_clean_off];
1576 if (GNUNET_YES == GNUNET_GNSRECORD_is_critical (rd[i].record_type))
1577 rd_clean[rd_clean_off].flags |= GNUNET_GNSRECORD_RF_CRITICAL;
1578 1596
1579 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) || 1597 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) ||
1580 (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type)) 1598 (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type))
@@ -1587,10 +1605,21 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1587 have_nick = GNUNET_YES; 1605 have_nick = GNUNET_YES;
1588 } 1606 }
1589 } 1607 }
1590 GNUNET_GNSRECORD_convert_records_for_export (rd, 1608 if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (conv_name,
1591 rd_clean_off, 1609 rd_clean,
1592 rd_clean, 1610 rd_clean_off,
1593 &new_block_exp); 1611 rd_nf,
1612 &rd_nf_count,
1613 &new_block_exp,
1614 GNUNET_YES,
1615 &emsg))
1616 {
1617 send_store_response (nc, res, emsg, rid);
1618 GNUNET_free (emsg);
1619 GNUNET_SERVICE_client_continue (nc->client);
1620 GNUNET_free (conv_name);
1621 return;
1622 }
1594 /* 1623 /*
1595 * If existing_block_exp is 0, then there was not record set 1624 * If existing_block_exp is 0, then there was not record set
1596 * and no tombstone. 1625 * and no tombstone.
@@ -1598,27 +1627,15 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1598 * new block expiration would be, we need to add a tombstone 1627 * new block expiration would be, we need to add a tombstone
1599 * or update it. 1628 * or update it.
1600 */ 1629 */
1601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1602 "New exp: %s\n",
1603 GNUNET_STRINGS_absolute_time_to_string (new_block_exp));
1604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1605 "Old exp: %s\n",
1606 GNUNET_STRINGS_absolute_time_to_string (existing_block_exp));
1607 if (GNUNET_TIME_absolute_cmp (new_block_exp, <=, existing_block_exp)) 1630 if (GNUNET_TIME_absolute_cmp (new_block_exp, <=, existing_block_exp))
1608 { 1631 {
1609 /* There was already a TS record in the set given */ 1632 rd_nf[rd_nf_count].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE;
1610 if (NULL != tombstone_record) 1633 rd_nf[rd_nf_count].expiration_time =
1611 { 1634 existing_block_exp.abs_value_us;
1612 tombstone_record->expiration_time = existing_block_exp.abs_value_us; 1635 rd_nf[rd_nf_count].data = NULL;
1613 } 1636 rd_nf[rd_nf_count].data_size = 0;
1614 else { 1637 rd_nf[rd_nf_count].flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1615 rd_clean[rd_clean_off].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE; 1638 rd_nf_count++;
1616 rd_clean[rd_clean_off].expiration_time = existing_block_exp.abs_value_us;
1617 rd_clean[rd_clean_off].data = NULL;
1618 rd_clean[rd_clean_off].data_size = 0;
1619 rd_clean[rd_clean_off].flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1620 rd_clean_off++;
1621 }
1622 } 1639 }
1623 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && 1640 if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) &&
1624 (GNUNET_NO == have_nick)) 1641 (GNUNET_NO == have_nick))
@@ -1629,17 +1646,13 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
1629 res = GSN_database->store_records (GSN_database->cls, 1646 res = GSN_database->store_records (GSN_database->cls,
1630 &rp_msg->private_key, 1647 &rp_msg->private_key,
1631 conv_name, 1648 conv_name,
1632 rd_clean_off, 1649 rd_nf_count,
1633 rd_clean); 1650 rd_nf);
1634 } 1651 }
1635 1652
1636 if (GNUNET_OK != res) 1653 if (GNUNET_OK != res)
1637 { 1654 {
1638 /* store not successful or zonemaster, not need to tell monitors */ 1655 /* store not successful or zonemaster, not need to tell monitors */
1639 send_store_response (nc, res, rid);
1640 GNUNET_SERVICE_client_continue (nc->client);
1641 GNUNET_free (conv_name);
1642 return;
1643 } 1656 }
1644 1657
1645 sa = GNUNET_malloc (sizeof(struct StoreActivity) 1658 sa = GNUNET_malloc (sizeof(struct StoreActivity)
diff --git a/src/namestore/namestore.h b/src/namestore/namestore.h
index 05a1d97ad..8391d9d74 100644
--- a/src/namestore/namestore.h
+++ b/src/namestore/namestore.h
@@ -113,6 +113,20 @@ struct RecordStoreResponseMessage
113 * #GNUNET_SYSERR on failure, #GNUNET_OK on success 113 * #GNUNET_SYSERR on failure, #GNUNET_OK on success
114 */ 114 */
115 int32_t op_result GNUNET_PACKED; 115 int32_t op_result GNUNET_PACKED;
116
117 /**
118 * Error message length
119 */
120 uint16_t emsg_len GNUNET_PACKED;
121
122 /**
123 * Reserved for alignment.
124 */
125 uint16_t reserved GNUNET_PACKED;
126
127 /**
128 * Followed by error message
129 */
116}; 130};
117 131
118 132
diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c
index d4d06bab9..bb2f7465f 100644
--- a/src/namestore/namestore_api.c
+++ b/src/namestore/namestore_api.c
@@ -346,6 +346,44 @@ check_rd (size_t rd_len, const void *rd_buf, unsigned int rd_count)
346 return GNUNET_OK; 346 return GNUNET_OK;
347} 347}
348 348
349/**
350 * Handle an incoming message of type
351 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
352 *
353 * @param cls
354 * @param msg the message we received
355 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
356 */
357static int
358check_record_store_response (void *cls,
359 const struct RecordStoreResponseMessage *msg)
360{
361 const char *emsg;
362 size_t msg_len;
363 size_t emsg_len;
364
365 (void) cls;
366 msg_len = ntohs (msg->gns_header.header.size);
367 emsg_len = ntohs (msg->emsg_len);
368 if (0 != ntohs (msg->reserved))
369 {
370 GNUNET_break (0);
371 return GNUNET_SYSERR;
372 }
373 if (msg_len != sizeof(struct RecordStoreResponseMessage) + emsg_len)
374 {
375 GNUNET_break (0);
376 return GNUNET_SYSERR;
377 }
378 emsg = (const char *) &msg[1];
379 if ((0 != emsg_len) && ('\0' != emsg[emsg_len - 1]))
380 {
381 GNUNET_break (0);
382 return GNUNET_SYSERR;
383 }
384 return GNUNET_OK;
385}
386
349 387
350/** 388/**
351 * Handle an incoming message of type 389 * Handle an incoming message of type
@@ -364,15 +402,11 @@ handle_record_store_response (void *cls,
364 const char *emsg; 402 const char *emsg;
365 403
366 qe = find_qe (h, ntohl (msg->gns_header.r_id)); 404 qe = find_qe (h, ntohl (msg->gns_header.r_id));
405 emsg = (const char *) &msg[1];
367 res = ntohl (msg->op_result); 406 res = ntohl (msg->op_result);
368 LOG (GNUNET_ERROR_TYPE_DEBUG, 407 LOG (GNUNET_ERROR_TYPE_DEBUG,
369 "Received RECORD_STORE_RESPONSE with result %d\n", 408 "Received RECORD_STORE_RESPONSE with result %d\n",
370 res); 409 res);
371 /* TODO: add actual error message from namestore to response... */
372 if (GNUNET_SYSERR == res)
373 emsg = _ ("Namestore failed to store record\n");
374 else
375 emsg = NULL;
376 if (NULL == qe) 410 if (NULL == qe)
377 return; 411 return;
378 if (NULL != qe->cont) 412 if (NULL != qe->cont)
@@ -775,7 +809,7 @@ static void
775reconnect (struct GNUNET_NAMESTORE_Handle *h) 809reconnect (struct GNUNET_NAMESTORE_Handle *h)
776{ 810{
777 struct GNUNET_MQ_MessageHandler handlers[] = 811 struct GNUNET_MQ_MessageHandler handlers[] =
778 { GNUNET_MQ_hd_fixed_size (record_store_response, 812 { GNUNET_MQ_hd_var_size (record_store_response,
779 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE, 813 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE,
780 struct RecordStoreResponseMessage, 814 struct RecordStoreResponseMessage,
781 h), 815 h),
diff --git a/src/zonemaster/gnunet-service-zonemaster-monitor.c b/src/zonemaster/gnunet-service-zonemaster-monitor.c
index fef9e6b82..6474228f4 100644
--- a/src/zonemaster/gnunet-service-zonemaster-monitor.c
+++ b/src/zonemaster/gnunet-service-zonemaster-monitor.c
@@ -288,6 +288,7 @@ handle_monitor_event (void *cls,
288 unsigned int rd_fresh_count; 288 unsigned int rd_fresh_count;
289 struct DhtPutActivity *ma; 289 struct DhtPutActivity *ma;
290 struct GNUNET_TIME_Absolute expire; 290 struct GNUNET_TIME_Absolute expire;
291 char *emsg;
291 292
292 (void) cls; 293 (void) cls;
293 GNUNET_STATISTICS_update (statistics, 294 GNUNET_STATISTICS_update (statistics,
@@ -300,10 +301,21 @@ handle_monitor_event (void *cls,
300 label); 301 label);
301 /* filter out records that are not public, and convert to 302 /* filter out records that are not public, and convert to
302 absolute expiration time. */ 303 absolute expiration time. */
303 rd_public_count = GNUNET_GNSRECORD_convert_records_for_export (rd, 304 if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label,
304 rd_count, 305 rd,
305 rd_public, 306 rd_count,
306 &expire); 307 rd_public,
308 &rd_public_count,
309 &expire,
310 &emsg))
311 {
312 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
313 "Zonemaster-monitor failed: %s\n", emsg);
314 GNUNET_free (emsg);
315 GNUNET_NAMESTORE_zone_monitor_next (zmon,
316 1);
317 return; /* nothing to do */
318 }
307 if (0 == rd_public_count) 319 if (0 == rd_public_count)
308 { 320 {
309 GNUNET_NAMESTORE_zone_monitor_next (zmon, 321 GNUNET_NAMESTORE_zone_monitor_next (zmon,
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c
index 9eb3432ee..c5dd3348d 100644
--- a/src/zonemaster/gnunet-service-zonemaster.c
+++ b/src/zonemaster/gnunet-service-zonemaster.c
@@ -692,13 +692,25 @@ put_gns_record (void *cls,
692 unsigned int rd_fresh_count = 0; 692 unsigned int rd_fresh_count = 0;
693 struct DhtPutActivity *ma; 693 struct DhtPutActivity *ma;
694 struct GNUNET_TIME_Absolute expire; 694 struct GNUNET_TIME_Absolute expire;
695 char *emsg;
695 696
696 (void) cls; 697 (void) cls;
697 ns_iteration_left--; 698 ns_iteration_left--;
698 rd_public_count = GNUNET_GNSRECORD_convert_records_for_export (rd, 699 if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label,
699 rd_count, 700 rd,
700 rd_public, 701 rd_count,
701 &expire); 702 rd_public,
703 &rd_public_count,
704 &expire,
705 &emsg))
706 {
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708 "Record set inconsistent, moving to next record set: %s\n",
709 emsg);
710 GNUNET_free (emsg);
711 check_zone_namestore_next ();
712 return;
713 }
702 if (0 == rd_public_count) 714 if (0 == rd_public_count)
703 { 715 {
704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,