diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2022-02-07 15:59:04 +0100 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2022-02-07 15:59:04 +0100 |
commit | 14b3c75ab523830f5c1744d5a0faa4168b4172a7 (patch) | |
tree | eecc64f41891b29f5c1edd42f9315a2ab2733c59 | |
parent | 1c89bfe03f45eef178a1e5a5d4d33057946ebf11 (diff) | |
download | gnunet-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.c | 137 | ||||
-rw-r--r-- | src/include/gnunet_gns_service.h | 6 | ||||
-rw-r--r-- | src/include/gnunet_gnsrecord_lib.h | 61 | ||||
-rw-r--r-- | src/namestore/gnunet-service-namestore.c | 103 | ||||
-rw-r--r-- | src/namestore/namestore.h | 14 | ||||
-rw-r--r-- | src/namestore/namestore_api.c | 46 | ||||
-rw-r--r-- | src/zonemaster/gnunet-service-zonemaster-monitor.c | 20 | ||||
-rw-r--r-- | src/zonemaster/gnunet-service-zonemaster.c | 20 |
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 | ||
402 | unsigned int | 403 | enum GNUNET_GenericReturnValue |
403 | GNUNET_GNSRECORD_convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, | 404 | GNUNET_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 | |||
525 | enum GNUNET_GenericReturnValue | ||
526 | GNUNET_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 | */ |
59 | struct GNUNET_GNS_Handle; | 53 | struct 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 | */ |
620 | struct GNUNET_TIME_Absolute | 626 | struct GNUNET_TIME_Absolute |
621 | GNUNET_GNSRECORD_record_get_expiration_time (unsigned int rd_count, | 627 | GNUNET_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 | |||
710 | GNUNET_GNSRECORD_is_critical (uint32_t type); | 717 | GNUNET_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 | */ | ||
737 | enum GNUNET_GenericReturnValue | ||
738 | GNUNET_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 | */ |
723 | unsigned int | 761 | enum GNUNET_GenericReturnValue |
724 | GNUNET_GNSRECORD_convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, | 762 | GNUNET_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 | */ |
810 | static void | 810 | static void |
811 | send_store_response (struct NamestoreClient *nc, int res, uint32_t rid) | 811 | send_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 | */ | ||
357 | static int | ||
358 | check_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 | |||
775 | reconnect (struct GNUNET_NAMESTORE_Handle *h) | 809 | reconnect (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, |