diff options
Diffstat (limited to 'src/transport/gnunet-service-tng.c')
-rw-r--r-- | src/transport/gnunet-service-tng.c | 495 |
1 files changed, 360 insertions, 135 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c index 2f7129478..d3c3defec 100644 --- a/src/transport/gnunet-service-tng.c +++ b/src/transport/gnunet-service-tng.c | |||
@@ -24,15 +24,7 @@ | |||
24 | * | 24 | * |
25 | * TODO: | 25 | * TODO: |
26 | * Implement next: | 26 | * Implement next: |
27 | * - FIXME: handle_client_send(): pick DVH path, and box | ||
28 | * message accordingly (if applicable, see FIXMEs) | ||
29 | * - proper use/initialization of timestamps in messages exchanged | ||
30 | * during DV learning | ||
31 | * - persistence of monotonic time from DVInit to prevent | ||
32 | * replay attacks using DVInit messages | ||
33 | * - dv hop-by-hop signature verification (at least at initiator) | 27 | * - dv hop-by-hop signature verification (at least at initiator) |
34 | * - persistence of monotonic time obtained from other peers | ||
35 | * in PEERSTORE (by message type) -- done for backchannel, needed elsewhere? | ||
36 | * - change transport-core API to provide proper flow control in both | 28 | * - change transport-core API to provide proper flow control in both |
37 | * directions, allow multiple messages per peer simultaneously (tag | 29 | * directions, allow multiple messages per peer simultaneously (tag |
38 | * confirmations with unique message ID), and replace quota-out with | 30 | * confirmations with unique message ID), and replace quota-out with |
@@ -720,6 +712,20 @@ struct TransportDVLearnMessage | |||
720 | struct GNUNET_TIME_RelativeNBO non_network_delay; | 712 | struct GNUNET_TIME_RelativeNBO non_network_delay; |
721 | 713 | ||
722 | /** | 714 | /** |
715 | * Time at the initiator when generating the signature. | ||
716 | * | ||
717 | * Note that the receiver MUST IGNORE the absolute time, and only interpret | ||
718 | * the value as a mononic time and reject "older" values than the last one | ||
719 | * observed. This is necessary as we do not want to require synchronized | ||
720 | * clocks and may not have a bidirectional communication channel. | ||
721 | * | ||
722 | * Even with this, there is no real guarantee against replay achieved here, | ||
723 | * unless the latest timestamp is persisted. Persistence should be | ||
724 | * provided via PEERSTORE if possible. | ||
725 | */ | ||
726 | struct GNUNET_TIME_AbsoluteNBO monotonic_time; | ||
727 | |||
728 | /** | ||
723 | * Signature of this hop over the path, of purpose | 729 | * Signature of this hop over the path, of purpose |
724 | * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR | 730 | * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR |
725 | */ | 731 | */ |
@@ -923,6 +929,41 @@ enum ClientType | |||
923 | 929 | ||
924 | 930 | ||
925 | /** | 931 | /** |
932 | * Which transmission options are allowable for transmission? | ||
933 | * Interpreted bit-wise! | ||
934 | */ | ||
935 | enum RouteMessageOptions | ||
936 | { | ||
937 | /** | ||
938 | * Only confirmed, non-DV direct neighbours. | ||
939 | */ | ||
940 | RMO_NONE = 0, | ||
941 | |||
942 | /** | ||
943 | * We are allowed to use DV routing for this @a hdr | ||
944 | */ | ||
945 | RMO_DV_ALLOWED = 1, | ||
946 | |||
947 | /** | ||
948 | * We are allowed to use unconfirmed queues or DV routes for this message | ||
949 | */ | ||
950 | RMO_UNCONFIRMED_ALLOWED = 2, | ||
951 | |||
952 | /** | ||
953 | * Reliable and unreliable, DV and non-DV are all acceptable. | ||
954 | */ | ||
955 | RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED), | ||
956 | |||
957 | /** | ||
958 | * If we have multiple choices, it is OK to send this message | ||
959 | * over multiple channels at the same time to improve loss tolerance. | ||
960 | * (We do at most 2 transmissions.) | ||
961 | */ | ||
962 | RMO_REDUNDANT = 4 | ||
963 | }; | ||
964 | |||
965 | |||
966 | /** | ||
926 | * When did we launch this DV learning activity? | 967 | * When did we launch this DV learning activity? |
927 | */ | 968 | */ |
928 | struct LearnLaunchEntry | 969 | struct LearnLaunchEntry |
@@ -1629,6 +1670,18 @@ struct Neighbour | |||
1629 | struct GNUNET_SCHEDULER_Task *timeout_task; | 1670 | struct GNUNET_SCHEDULER_Task *timeout_task; |
1630 | 1671 | ||
1631 | /** | 1672 | /** |
1673 | * Handle for an operation to fetch @e last_dv_learn_monotime information from | ||
1674 | * the PEERSTORE, or NULL. | ||
1675 | */ | ||
1676 | struct GNUNET_PEERSTORE_IterateContext *get; | ||
1677 | |||
1678 | /** | ||
1679 | * Handle to a PEERSTORE store operation to store this @e pid's @e | ||
1680 | * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending. | ||
1681 | */ | ||
1682 | struct GNUNET_PEERSTORE_StoreContext *sc; | ||
1683 | |||
1684 | /** | ||
1632 | * Quota at which CORE is allowed to transmit to this peer | 1685 | * Quota at which CORE is allowed to transmit to this peer |
1633 | * (note that the value CORE should actually be told is this | 1686 | * (note that the value CORE should actually be told is this |
1634 | * value plus the respective value in `struct DistanceVector`). | 1687 | * value plus the respective value in `struct DistanceVector`). |
@@ -1643,6 +1696,12 @@ struct Neighbour | |||
1643 | struct GNUNET_BANDWIDTH_Value32NBO quota_out; | 1696 | struct GNUNET_BANDWIDTH_Value32NBO quota_out; |
1644 | 1697 | ||
1645 | /** | 1698 | /** |
1699 | * Latest DVLearn monotonic time seen from this peer. Initialized only | ||
1700 | * if @e dl_monotime_available is #GNUNET_YES. | ||
1701 | */ | ||
1702 | struct GNUNET_TIME_Absolute last_dv_learn_monotime; | ||
1703 | |||
1704 | /** | ||
1646 | * What is the earliest timeout of any message in @e pending_msg_tail? | 1705 | * What is the earliest timeout of any message in @e pending_msg_tail? |
1647 | */ | 1706 | */ |
1648 | struct GNUNET_TIME_Absolute earliest_timeout; | 1707 | struct GNUNET_TIME_Absolute earliest_timeout; |
@@ -1652,6 +1711,12 @@ struct Neighbour | |||
1652 | * CORE? | 1711 | * CORE? |
1653 | */ | 1712 | */ |
1654 | int core_visible; | 1713 | int core_visible; |
1714 | |||
1715 | /** | ||
1716 | * Do we have the lastest value for @e last_dv_learn_monotime from | ||
1717 | * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE? | ||
1718 | */ | ||
1719 | int dv_monotime_available; | ||
1655 | }; | 1720 | }; |
1656 | 1721 | ||
1657 | 1722 | ||
@@ -2851,7 +2916,20 @@ free_neighbour (struct Neighbour *neighbour) | |||
2851 | free_dv_route (dv); | 2916 | free_dv_route (dv); |
2852 | } | 2917 | } |
2853 | if (NULL != neighbour->reassembly_timeout_task) | 2918 | if (NULL != neighbour->reassembly_timeout_task) |
2919 | { | ||
2854 | GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task); | 2920 | GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task); |
2921 | neighbour->reassembly_timeout_task = NULL; | ||
2922 | } | ||
2923 | if (NULL != neighbour->get) | ||
2924 | { | ||
2925 | GNUNET_PEERSTORE_iterate_cancel (neighbour->get); | ||
2926 | neighbour->get = NULL; | ||
2927 | } | ||
2928 | if (NULL != neighbour->sc) | ||
2929 | { | ||
2930 | GNUNET_PEERSTORE_store_cancel (neighbour->sc); | ||
2931 | neighbour->sc = NULL; | ||
2932 | } | ||
2855 | GNUNET_free (neighbour); | 2933 | GNUNET_free (neighbour); |
2856 | } | 2934 | } |
2857 | 2935 | ||
@@ -3453,6 +3531,130 @@ check_queue_timeouts (void *cls) | |||
3453 | 3531 | ||
3454 | 3532 | ||
3455 | /** | 3533 | /** |
3534 | * Create a DV Box message. | ||
3535 | * | ||
3536 | * @param total_hops how many hops did the message take so far | ||
3537 | * @param num_hops length of the @a hops array | ||
3538 | * @param origin origin of the message | ||
3539 | * @param hops next peer(s) to the destination, including destination | ||
3540 | * @param payload payload of the box | ||
3541 | * @param payload_size number of bytes in @a payload | ||
3542 | * @return boxed message (caller must #GNUNET_free() it). | ||
3543 | */ | ||
3544 | static struct TransportDVBoxMessage * | ||
3545 | create_dv_box (uint16_t total_hops, | ||
3546 | const struct GNUNET_PeerIdentity *origin, | ||
3547 | const struct GNUNET_PeerIdentity *target, | ||
3548 | uint16_t num_hops, | ||
3549 | const struct GNUNET_PeerIdentity *hops, | ||
3550 | const void *payload, | ||
3551 | uint16_t payload_size) | ||
3552 | { | ||
3553 | struct TransportDVBoxMessage *dvb; | ||
3554 | struct GNUNET_PeerIdentity *dhops; | ||
3555 | |||
3556 | GNUNET_assert (UINT16_MAX < | ||
3557 | sizeof (struct TransportDVBoxMessage) + | ||
3558 | sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + | ||
3559 | payload_size); | ||
3560 | dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) + | ||
3561 | sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + | ||
3562 | payload_size); | ||
3563 | dvb->header.size = | ||
3564 | htons (sizeof (struct TransportDVBoxMessage) + | ||
3565 | sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size); | ||
3566 | dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX); | ||
3567 | dvb->total_hops = htons (total_hops); | ||
3568 | dvb->num_hops = htons (num_hops + 1); | ||
3569 | dvb->origin = *origin; | ||
3570 | dhops = (struct GNUNET_PeerIdentity *) &dvb[1]; | ||
3571 | memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity)); | ||
3572 | dhops[num_hops] = *target; | ||
3573 | memcpy (&dhops[num_hops + 1], payload, payload_size); | ||
3574 | return dvb; | ||
3575 | } | ||
3576 | |||
3577 | |||
3578 | /** | ||
3579 | * Pick @a hops_array_length random DV paths satisfying @a options | ||
3580 | * | ||
3581 | * @param dv data structure to pick paths from | ||
3582 | * @param options constraints to satisfy | ||
3583 | * @param hops_array[out] set to the result | ||
3584 | * @param hops_array_length length of the @a hops_array | ||
3585 | * @return number of entries set in @a hops_array | ||
3586 | */ | ||
3587 | static unsigned int | ||
3588 | pick_random_dv_hops (const struct DistanceVector *dv, | ||
3589 | enum RouteMessageOptions options, | ||
3590 | struct DistanceVectorHop **hops_array, | ||
3591 | unsigned int hops_array_length) | ||
3592 | { | ||
3593 | uint64_t choices[hops_array_length]; | ||
3594 | uint64_t num_dv; | ||
3595 | unsigned int dv_count; | ||
3596 | |||
3597 | /* Pick random vectors, but weighted by distance, giving more weight | ||
3598 | to shorter vectors */ | ||
3599 | num_dv = 0; | ||
3600 | dv_count = 0; | ||
3601 | for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos; | ||
3602 | pos = pos->next_dv) | ||
3603 | { | ||
3604 | if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) && | ||
3605 | (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until) | ||
3606 | .rel_value_us == 0)) | ||
3607 | continue; /* pos unconfirmed and confirmed required */ | ||
3608 | num_dv += MAX_DV_HOPS_ALLOWED - pos->distance; | ||
3609 | dv_count++; | ||
3610 | } | ||
3611 | if (0 == dv_count) | ||
3612 | return 0; | ||
3613 | if (dv_count <= hops_array_length) | ||
3614 | { | ||
3615 | dv_count = 0; | ||
3616 | for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos; | ||
3617 | pos = pos->next_dv) | ||
3618 | hops_array[dv_count++] = pos; | ||
3619 | return dv_count; | ||
3620 | } | ||
3621 | for (unsigned int i = 0; i < hops_array_length; i++) | ||
3622 | { | ||
3623 | int ok = GNUNET_NO; | ||
3624 | while (GNUNET_NO == ok) | ||
3625 | { | ||
3626 | choices[i] = | ||
3627 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv); | ||
3628 | ok = GNUNET_YES; | ||
3629 | for (unsigned int j = 0; j < i; j++) | ||
3630 | if (choices[i] == choices[j]) | ||
3631 | { | ||
3632 | ok = GNUNET_NO; | ||
3633 | break; | ||
3634 | } | ||
3635 | } | ||
3636 | } | ||
3637 | dv_count = 0; | ||
3638 | num_dv = 0; | ||
3639 | for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos; | ||
3640 | pos = pos->next_dv) | ||
3641 | { | ||
3642 | uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance; | ||
3643 | |||
3644 | if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) && | ||
3645 | (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until) | ||
3646 | .rel_value_us == 0)) | ||
3647 | continue; /* pos unconfirmed and confirmed required */ | ||
3648 | for (unsigned int i = 0; i < hops_array_length; i++) | ||
3649 | if ((num_dv <= choices[i]) && (num_dv + delta > choices[i])) | ||
3650 | hops_array[dv_count++] = pos; | ||
3651 | num_dv += delta; | ||
3652 | } | ||
3653 | return dv_count; | ||
3654 | } | ||
3655 | |||
3656 | |||
3657 | /** | ||
3456 | * Client asked for transmission to a peer. Process the request. | 3658 | * Client asked for transmission to a peer. Process the request. |
3457 | * | 3659 | * |
3458 | * @param cls the client | 3660 | * @param cls the client |
@@ -3471,6 +3673,7 @@ handle_client_send (void *cls, const struct OutboundMessage *obm) | |||
3471 | int was_empty; | 3673 | int was_empty; |
3472 | const void *payload; | 3674 | const void *payload; |
3473 | size_t payload_size; | 3675 | size_t payload_size; |
3676 | struct TransportDVBoxMessage *dvb; | ||
3474 | 3677 | ||
3475 | GNUNET_assert (CT_CORE == tc->type); | 3678 | GNUNET_assert (CT_CORE == tc->type); |
3476 | obmm = (const struct GNUNET_MessageHeader *) &obm[1]; | 3679 | obmm = (const struct GNUNET_MessageHeader *) &obm[1]; |
@@ -3504,18 +3707,26 @@ handle_client_send (void *cls, const struct OutboundMessage *obm) | |||
3504 | } | 3707 | } |
3505 | if (NULL == target) | 3708 | if (NULL == target) |
3506 | { | 3709 | { |
3507 | // FIXME: overall, similar logic exists already for DV boxing, | 3710 | unsigned int res; |
3508 | // re-use! | 3711 | struct DistanceVectorHop *dvh; |
3509 | 3712 | ||
3510 | // FIXME: dvh = pick_dv_hop (dv); | 3713 | res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1); |
3714 | GNUNET_assert (1 == res); | ||
3511 | target = dvh->next_hop; | 3715 | target = dvh->next_hop; |
3512 | // FIXME: dv box message here! | 3716 | dvb = create_dv_box (0, |
3513 | // FIXME: set payload & payload_size to box (and free box below!) | 3717 | &GST_my_identity, |
3718 | &obm->peer, | ||
3719 | dvh->distance, | ||
3720 | dvh->path, | ||
3721 | &obm[1], | ||
3722 | bytes_msg); | ||
3723 | payload = dvb; | ||
3724 | payload_size = ntohs (dvb->header.size); | ||
3514 | } | 3725 | } |
3515 | else | 3726 | else |
3516 | { | 3727 | { |
3517 | dvh = NULL; | 3728 | dvh = NULL; |
3518 | // box = NULL; | 3729 | dvb = NULL; |
3519 | payload = &obm[1]; | 3730 | payload = &obm[1]; |
3520 | payload_size = bytes_msg; | 3731 | payload_size = bytes_msg; |
3521 | } | 3732 | } |
@@ -3527,8 +3738,9 @@ handle_client_send (void *cls, const struct OutboundMessage *obm) | |||
3527 | pm->bytes_msg = payload_size; | 3738 | pm->bytes_msg = payload_size; |
3528 | pm->timeout = | 3739 | pm->timeout = |
3529 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout)); | 3740 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout)); |
3530 | memcpy (&pm[1], &obm[1], payload_size); | 3741 | memcpy (&pm[1], payload, payload_size); |
3531 | // FIXME: GNUNET_free_non_null (box); | 3742 | GNUNET_free_non_null (dvb); |
3743 | dvb = NULL; | ||
3532 | pm->dvh = dvh; | 3744 | pm->dvh = dvh; |
3533 | if (NULL != dvh) | 3745 | if (NULL != dvh) |
3534 | { | 3746 | { |
@@ -3810,41 +4022,6 @@ queue_send_msg (struct Queue *queue, | |||
3810 | 4022 | ||
3811 | 4023 | ||
3812 | /** | 4024 | /** |
3813 | * Which transmission options are allowable for transmission? | ||
3814 | * Interpreted bit-wise! | ||
3815 | */ | ||
3816 | enum RouteMessageOptions | ||
3817 | { | ||
3818 | /** | ||
3819 | * Only confirmed, non-DV direct neighbours. | ||
3820 | */ | ||
3821 | RMO_NONE = 0, | ||
3822 | |||
3823 | /** | ||
3824 | * We are allowed to use DV routing for this @a hdr | ||
3825 | */ | ||
3826 | RMO_DV_ALLOWED = 1, | ||
3827 | |||
3828 | /** | ||
3829 | * We are allowed to use unconfirmed queues or DV routes for this message | ||
3830 | */ | ||
3831 | RMO_UNCONFIRMED_ALLOWED = 2, | ||
3832 | |||
3833 | /** | ||
3834 | * Reliable and unreliable, DV and non-DV are all acceptable. | ||
3835 | */ | ||
3836 | RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED), | ||
3837 | |||
3838 | /** | ||
3839 | * If we have multiple choices, it is OK to send this message | ||
3840 | * over multiple channels at the same time to improve loss tolerance. | ||
3841 | * (We do at most 2 transmissions.) | ||
3842 | */ | ||
3843 | RMO_REDUNDANT = 4 | ||
3844 | }; | ||
3845 | |||
3846 | |||
3847 | /** | ||
3848 | * Pick a queue of @a n under constraints @a options and schedule | 4025 | * Pick a queue of @a n under constraints @a options and schedule |
3849 | * transmission of @a hdr. | 4026 | * transmission of @a hdr. |
3850 | * | 4027 | * |
@@ -3927,22 +4104,17 @@ forward_via_dvh (const struct DistanceVectorHop *dvh, | |||
3927 | const struct GNUNET_MessageHeader *payload, | 4104 | const struct GNUNET_MessageHeader *payload, |
3928 | enum RouteMessageOptions options) | 4105 | enum RouteMessageOptions options) |
3929 | { | 4106 | { |
3930 | uint16_t mlen = ntohs (payload->size); | 4107 | struct TransportDVBoxMessage *dvb; |
3931 | char boxram[sizeof (struct TransportDVBoxMessage) + | ||
3932 | (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) + | ||
3933 | mlen] GNUNET_ALIGN; | ||
3934 | struct TransportDVBoxMessage *box = (struct TransportDVBoxMessage *) boxram; | ||
3935 | struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1]; | ||
3936 | 4108 | ||
3937 | box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX); | 4109 | dvb = create_dv_box (0, |
3938 | box->header.size = htons (sizeof (boxram)); | 4110 | &GST_my_identity, |
3939 | box->total_hops = htons (0); | 4111 | &dvh->dv->target, |
3940 | box->num_hops = htons (dvh->distance + 1); | 4112 | dvh->distance, |
3941 | box->origin = GST_my_identity; | 4113 | dvh->path, |
3942 | memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity)); | 4114 | payload, |
3943 | path[dvh->distance] = dvh->dv->target; | 4115 | ntohs (payload->size)); |
3944 | memcpy (&path[dvh->distance + 1], payload, mlen); | 4116 | route_via_neighbour (dvh->next_hop, &dvb->header, options); |
3945 | route_via_neighbour (dvh->next_hop, &box->header, options); | 4117 | GNUNET_free (dvb); |
3946 | } | 4118 | } |
3947 | 4119 | ||
3948 | 4120 | ||
@@ -3960,52 +4132,15 @@ route_via_dv (const struct DistanceVector *dv, | |||
3960 | const struct GNUNET_MessageHeader *hdr, | 4132 | const struct GNUNET_MessageHeader *hdr, |
3961 | enum RouteMessageOptions options) | 4133 | enum RouteMessageOptions options) |
3962 | { | 4134 | { |
3963 | struct DistanceVectorHop *h1; | 4135 | struct DistanceVectorHop *hops[2]; |
3964 | struct DistanceVectorHop *h2; | 4136 | unsigned int res; |
3965 | uint64_t num_dv; | ||
3966 | uint64_t choice1; | ||
3967 | uint64_t choice2; | ||
3968 | |||
3969 | /* Pick random vectors, but weighted by distance, giving more weight | ||
3970 | to shorter vectors */ | ||
3971 | num_dv = 0; | ||
3972 | for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos; | ||
3973 | pos = pos->next_dv) | ||
3974 | { | ||
3975 | if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) && | ||
3976 | (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until) | ||
3977 | .rel_value_us == 0)) | ||
3978 | continue; /* pos unconfirmed and confirmed required */ | ||
3979 | num_dv += MAX_DV_HOPS_ALLOWED - pos->distance; | ||
3980 | } | ||
3981 | if (0 == num_dv) | ||
3982 | { | ||
3983 | GNUNET_break (0); | ||
3984 | return; | ||
3985 | } | ||
3986 | choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv); | ||
3987 | choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv); | ||
3988 | num_dv = 0; | ||
3989 | h1 = NULL; | ||
3990 | h2 = NULL; | ||
3991 | for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos; | ||
3992 | pos = pos->next_dv) | ||
3993 | { | ||
3994 | uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance; | ||
3995 | 4137 | ||
3996 | if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) && | 4138 | res = pick_random_dv_hops (dv, |
3997 | (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until) | 4139 | options, |
3998 | .rel_value_us == 0)) | 4140 | hops, |
3999 | continue; /* pos unconfirmed and confirmed required */ | 4141 | (0 == (options & RMO_REDUNDANT)) ? 1 : 2); |
4000 | if ((num_dv <= choice1) && (num_dv + delta > choice1)) | 4142 | for (unsigned int i = 0; i < res; i++) |
4001 | h1 = pos; | 4143 | forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT)); |
4002 | if ((num_dv <= choice2) && (num_dv + delta > choice2)) | ||
4003 | h2 = pos; | ||
4004 | num_dv += delta; | ||
4005 | } | ||
4006 | forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT)); | ||
4007 | if (0 == (options & RMO_REDUNDANT)) | ||
4008 | forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT)); | ||
4009 | } | 4144 | } |
4010 | 4145 | ||
4011 | 4146 | ||
@@ -5912,6 +6047,7 @@ forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop, | |||
5912 | /** | 6047 | /** |
5913 | * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR | 6048 | * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR |
5914 | * | 6049 | * |
6050 | * @param sender_monotonic_time monotonic time of the initiator | ||
5915 | * @param init the signer | 6051 | * @param init the signer |
5916 | * @param challenge the challenge that was signed | 6052 | * @param challenge the challenge that was signed |
5917 | * @param init_sig signature presumably by @a init | 6053 | * @param init_sig signature presumably by @a init |
@@ -5919,6 +6055,7 @@ forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop, | |||
5919 | */ | 6055 | */ |
5920 | static int | 6056 | static int |
5921 | validate_dv_initiator_signature ( | 6057 | validate_dv_initiator_signature ( |
6058 | struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time, | ||
5922 | const struct GNUNET_PeerIdentity *init, | 6059 | const struct GNUNET_PeerIdentity *init, |
5923 | const struct ChallengeNonceP *challenge, | 6060 | const struct ChallengeNonceP *challenge, |
5924 | const struct GNUNET_CRYPTO_EddsaSignature *init_sig) | 6061 | const struct GNUNET_CRYPTO_EddsaSignature *init_sig) |
@@ -5926,6 +6063,7 @@ validate_dv_initiator_signature ( | |||
5926 | struct DvInitPS ip = {.purpose.purpose = htonl ( | 6063 | struct DvInitPS ip = {.purpose.purpose = htonl ( |
5927 | GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR), | 6064 | GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR), |
5928 | .purpose.size = htonl (sizeof (ip)), | 6065 | .purpose.size = htonl (sizeof (ip)), |
6066 | .monotonic_time = sender_monotonic_time, | ||
5929 | .challenge = *challenge}; | 6067 | .challenge = *challenge}; |
5930 | 6068 | ||
5931 | if ( | 6069 | if ( |
@@ -6132,6 +6270,24 @@ calculate_fork_degree (unsigned int hops_taken, | |||
6132 | 6270 | ||
6133 | 6271 | ||
6134 | /** | 6272 | /** |
6273 | * Function called when peerstore is done storing a DV monotonic time. | ||
6274 | * | ||
6275 | * @param cls a `struct Neighbour` | ||
6276 | * @param success #GNUNET_YES if peerstore was successful | ||
6277 | */ | ||
6278 | static void | ||
6279 | neighbour_store_dvmono_cb (void *cls, int success) | ||
6280 | { | ||
6281 | struct Neighbour *n = cls; | ||
6282 | |||
6283 | n->sc = NULL; | ||
6284 | if (GNUNET_YES != success) | ||
6285 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
6286 | "Failed to store other peer's monotonic time in peerstore!\n"); | ||
6287 | } | ||
6288 | |||
6289 | |||
6290 | /** | ||
6135 | * Communicator gave us a DV learn message. Process the request. | 6291 | * Communicator gave us a DV learn message. Process the request. |
6136 | * | 6292 | * |
6137 | * @param cls a `struct CommunicatorMessageContext` (must call | 6293 | * @param cls a `struct CommunicatorMessageContext` (must call |
@@ -6150,6 +6306,7 @@ handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl) | |||
6150 | int do_fwd; | 6306 | int do_fwd; |
6151 | int did_initiator; | 6307 | int did_initiator; |
6152 | struct GNUNET_TIME_Absolute in_time; | 6308 | struct GNUNET_TIME_Absolute in_time; |
6309 | struct Neighbour *n; | ||
6153 | 6310 | ||
6154 | nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */ | 6311 | nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */ |
6155 | bi_history = ntohs (dvl->bidirectional); | 6312 | bi_history = ntohs (dvl->bidirectional); |
@@ -6184,15 +6341,44 @@ handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl) | |||
6184 | /* continue communicator here, everything else can happen asynchronous! */ | 6341 | /* continue communicator here, everything else can happen asynchronous! */ |
6185 | finish_cmc_handling (cmc); | 6342 | finish_cmc_handling (cmc); |
6186 | 6343 | ||
6187 | /* OPTIMIZE-FIXME: Technically, we only need to bother checking | 6344 | n = lookup_neighbour (&dvl->initiator); |
6188 | the initiator signature if we send the message back to the initiator... | 6345 | if (NULL != n) |
6189 | */ | ||
6190 | if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator, | ||
6191 | &dvl->challenge, | ||
6192 | &dvl->init_sig)) | ||
6193 | { | 6346 | { |
6194 | GNUNET_break_op (0); | 6347 | if ((n->dv_monotime_available == GNUNET_YES) && |
6195 | return; | 6348 | (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us < |
6349 | n->last_dv_learn_monotime.abs_value_us)) | ||
6350 | { | ||
6351 | GNUNET_STATISTICS_update (GST_stats, | ||
6352 | "# DV learn discarded due to time travel", | ||
6353 | 1, | ||
6354 | GNUNET_NO); | ||
6355 | return; | ||
6356 | } | ||
6357 | if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time, | ||
6358 | &dvl->initiator, | ||
6359 | &dvl->challenge, | ||
6360 | &dvl->init_sig)) | ||
6361 | { | ||
6362 | GNUNET_break_op (0); | ||
6363 | return; | ||
6364 | } | ||
6365 | n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time); | ||
6366 | if (GNUNET_YES == n->dv_monotime_available) | ||
6367 | { | ||
6368 | if (NULL != n->sc) | ||
6369 | GNUNET_PEERSTORE_store_cancel (n->sc); | ||
6370 | n->sc = | ||
6371 | GNUNET_PEERSTORE_store (peerstore, | ||
6372 | "transport", | ||
6373 | &dvl->initiator, | ||
6374 | GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME, | ||
6375 | &dvl->monotonic_time, | ||
6376 | sizeof (dvl->monotonic_time), | ||
6377 | GNUNET_TIME_UNIT_FOREVER_ABS, | ||
6378 | GNUNET_PEERSTORE_STOREOPTION_REPLACE, | ||
6379 | &neighbour_store_dvmono_cb, | ||
6380 | n); | ||
6381 | } | ||
6196 | } | 6382 | } |
6197 | // FIXME: asynchronously (!) verify hop-by-hop signatures! | 6383 | // FIXME: asynchronously (!) verify hop-by-hop signatures! |
6198 | // => if signature verification load too high, implement random drop | 6384 | // => if signature verification load too high, implement random drop |
@@ -6418,25 +6604,16 @@ forward_dv_box (struct Neighbour *next_hop, | |||
6418 | uint16_t payload_size) | 6604 | uint16_t payload_size) |
6419 | { | 6605 | { |
6420 | struct TransportDVBoxMessage *dvb; | 6606 | struct TransportDVBoxMessage *dvb; |
6421 | struct GNUNET_PeerIdentity *dhops; | ||
6422 | 6607 | ||
6423 | GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBoxMessage) + | 6608 | dvb = create_dv_box (total_hops, |
6424 | sizeof (struct GNUNET_PeerIdentity) * num_hops + | 6609 | origin, |
6425 | payload_size); | 6610 | &hops[num_hops - 1] /* == target */, |
6426 | dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) + | 6611 | num_hops - 1 /* do not count target twice */, |
6427 | sizeof (struct GNUNET_PeerIdentity) * num_hops + | 6612 | hops, |
6613 | payload, | ||
6428 | payload_size); | 6614 | payload_size); |
6429 | dvb->header.size = | ||
6430 | htons (sizeof (struct TransportDVBoxMessage) + | ||
6431 | sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size); | ||
6432 | dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX); | ||
6433 | dvb->total_hops = htons (total_hops); | ||
6434 | dvb->num_hops = htons (num_hops); | ||
6435 | dvb->origin = *origin; | ||
6436 | dhops = (struct GNUNET_PeerIdentity *) &dvb[1]; | ||
6437 | memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity)); | ||
6438 | memcpy (&dhops[num_hops], payload, payload_size); | ||
6439 | route_message (&next_hop->pid, &dvb->header, RMO_NONE); | 6615 | route_message (&next_hop->pid, &dvb->header, RMO_NONE); |
6616 | GNUNET_free (dvb); | ||
6440 | } | 6617 | } |
6441 | 6618 | ||
6442 | 6619 | ||
@@ -7974,10 +8151,13 @@ start_dv_learn (void *cls) | |||
7974 | dvl.num_hops = htons (0); | 8151 | dvl.num_hops = htons (0); |
7975 | dvl.bidirectional = htons (0); | 8152 | dvl.bidirectional = htons (0); |
7976 | dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); | 8153 | dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); |
8154 | dvl.monotonic_time = | ||
8155 | GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg)); | ||
7977 | { | 8156 | { |
7978 | struct DvInitPS dvip = {.purpose.purpose = htonl ( | 8157 | struct DvInitPS dvip = {.purpose.purpose = htonl ( |
7979 | GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR), | 8158 | GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR), |
7980 | .purpose.size = htonl (sizeof (dvip)), | 8159 | .purpose.size = htonl (sizeof (dvip)), |
8160 | .monotonic_time = dvl.monotonic_time, | ||
7981 | .challenge = lle->challenge}; | 8161 | .challenge = lle->challenge}; |
7982 | 8162 | ||
7983 | GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, | 8163 | GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, |
@@ -8039,6 +8219,44 @@ check_validation_request_pending (void *cls, | |||
8039 | 8219 | ||
8040 | 8220 | ||
8041 | /** | 8221 | /** |
8222 | * Function called with the monotonic time of a DV initiator | ||
8223 | * by PEERSTORE. Updates the time. | ||
8224 | * | ||
8225 | * @param cls a `struct Neighbour` | ||
8226 | * @param record the information found, NULL for the last call | ||
8227 | * @param emsg error message | ||
8228 | */ | ||
8229 | static void | ||
8230 | neighbour_dv_monotime_cb (void *cls, | ||
8231 | const struct GNUNET_PEERSTORE_Record *record, | ||
8232 | const char *emsg) | ||
8233 | { | ||
8234 | struct Neighbour *n = cls; | ||
8235 | struct GNUNET_TIME_AbsoluteNBO *mtbe; | ||
8236 | struct GNUNET_TIME_Absolute mt; | ||
8237 | |||
8238 | (void) emsg; | ||
8239 | if (NULL == record) | ||
8240 | { | ||
8241 | /* we're done with #neighbour_dv_monotime_cb() invocations, | ||
8242 | continue normal processing */ | ||
8243 | n->get = NULL; | ||
8244 | n->dv_monotime_available = GNUNET_YES; | ||
8245 | return; | ||
8246 | } | ||
8247 | if (sizeof (*mtbe) != record->value_size) | ||
8248 | { | ||
8249 | GNUNET_break (0); | ||
8250 | return; | ||
8251 | } | ||
8252 | mtbe = record->value; | ||
8253 | n->last_dv_learn_monotime = | ||
8254 | GNUNET_TIME_absolute_max (n->last_dv_learn_monotime, | ||
8255 | GNUNET_TIME_absolute_ntoh (*mtbe)); | ||
8256 | } | ||
8257 | |||
8258 | |||
8259 | /** | ||
8042 | * New queue became available. Process the request. | 8260 | * New queue became available. Process the request. |
8043 | * | 8261 | * |
8044 | * @param cls the client | 8262 | * @param cls the client |
@@ -8074,6 +8292,13 @@ handle_add_queue_message (void *cls, | |||
8074 | &neighbour->pid, | 8292 | &neighbour->pid, |
8075 | neighbour, | 8293 | neighbour, |
8076 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | 8294 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
8295 | neighbour->get = | ||
8296 | GNUNET_PEERSTORE_iterate (peerstore, | ||
8297 | "transport", | ||
8298 | &neighbour->pid, | ||
8299 | GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME, | ||
8300 | &neighbour_dv_monotime_cb, | ||
8301 | neighbour); | ||
8077 | } | 8302 | } |
8078 | addr_len = ntohs (aqm->header.size) - sizeof (*aqm); | 8303 | addr_len = ntohs (aqm->header.size) - sizeof (*aqm); |
8079 | addr = (const char *) &aqm[1]; | 8304 | addr = (const char *) &aqm[1]; |