aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-04-25 13:44:49 +0200
committerChristian Grothoff <christian@grothoff.org>2019-04-25 13:44:49 +0200
commitc847f8c507d9d5af0c9c1398386f131563c3ae3e (patch)
treeb6f0ff6f8bebf5081d7e9fb5528694da7b91cfd6
parentf78be920bdff51d185ee0f53b1aeb84b5a8ae765 (diff)
downloadgnunet-c847f8c507d9d5af0c9c1398386f131563c3ae3e.tar.gz
gnunet-c847f8c507d9d5af0c9c1398386f131563c3ae3e.zip
implement DV learn monotime handling
-rw-r--r--src/include/gnunet_peerstore_service.h8
-rw-r--r--src/transport/gnunet-service-tng.c172
2 files changed, 166 insertions, 14 deletions
diff --git a/src/include/gnunet_peerstore_service.h b/src/include/gnunet_peerstore_service.h
index b20c1f3c7..ad80a3fa3 100644
--- a/src/include/gnunet_peerstore_service.h
+++ b/src/include/gnunet_peerstore_service.h
@@ -61,6 +61,14 @@ extern "C" {
61 "transport-backchannel-monotonic-time" 61 "transport-backchannel-monotonic-time"
62 62
63/** 63/**
64 * Key used to store sender's monotonic time from DV learn
65 * messages.
66 */
67#define GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME \
68 "transport-dv-learn-monotonic-time"
69
70
71/**
64 * Options for storing values in PEERSTORE 72 * Options for storing values in PEERSTORE
65 */ 73 */
66enum GNUNET_PEERSTORE_StoreOption 74enum GNUNET_PEERSTORE_StoreOption
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
index baf443f03..9fb8141bf 100644
--- a/src/transport/gnunet-service-tng.c
+++ b/src/transport/gnunet-service-tng.c
@@ -24,12 +24,6 @@
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 28 * - persistence of monotonic time obtained from other peers
35 * in PEERSTORE (by message type) -- done for backchannel, needed elsewhere? 29 * in PEERSTORE (by message type) -- done for backchannel, needed elsewhere?
@@ -720,6 +714,20 @@ struct TransportDVLearnMessage
720 struct GNUNET_TIME_RelativeNBO non_network_delay; 714 struct GNUNET_TIME_RelativeNBO non_network_delay;
721 715
722 /** 716 /**
717 * Time at the initiator when generating the signature.
718 *
719 * Note that the receiver MUST IGNORE the absolute time, and only interpret
720 * the value as a mononic time and reject "older" values than the last one
721 * observed. This is necessary as we do not want to require synchronized
722 * clocks and may not have a bidirectional communication channel.
723 *
724 * Even with this, there is no real guarantee against replay achieved here,
725 * unless the latest timestamp is persisted. Persistence should be
726 * provided via PEERSTORE if possible.
727 */
728 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
729
730 /**
723 * Signature of this hop over the path, of purpose 731 * Signature of this hop over the path, of purpose
724 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR 732 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
725 */ 733 */
@@ -1664,6 +1672,18 @@ struct Neighbour
1664 struct GNUNET_SCHEDULER_Task *timeout_task; 1672 struct GNUNET_SCHEDULER_Task *timeout_task;
1665 1673
1666 /** 1674 /**
1675 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1676 * the PEERSTORE, or NULL.
1677 */
1678 struct GNUNET_PEERSTORE_IterateContext *get;
1679
1680 /**
1681 * Handle to a PEERSTORE store operation to store this @e pid's @e
1682 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1683 */
1684 struct GNUNET_PEERSTORE_StoreContext *sc;
1685
1686 /**
1667 * Quota at which CORE is allowed to transmit to this peer 1687 * Quota at which CORE is allowed to transmit to this peer
1668 * (note that the value CORE should actually be told is this 1688 * (note that the value CORE should actually be told is this
1669 * value plus the respective value in `struct DistanceVector`). 1689 * value plus the respective value in `struct DistanceVector`).
@@ -1678,6 +1698,12 @@ struct Neighbour
1678 struct GNUNET_BANDWIDTH_Value32NBO quota_out; 1698 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1679 1699
1680 /** 1700 /**
1701 * Latest DVLearn monotonic time seen from this peer. Initialized only
1702 * if @e dl_monotime_available is #GNUNET_YES.
1703 */
1704 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1705
1706 /**
1681 * What is the earliest timeout of any message in @e pending_msg_tail? 1707 * What is the earliest timeout of any message in @e pending_msg_tail?
1682 */ 1708 */
1683 struct GNUNET_TIME_Absolute earliest_timeout; 1709 struct GNUNET_TIME_Absolute earliest_timeout;
@@ -1687,6 +1713,12 @@ struct Neighbour
1687 * CORE? 1713 * CORE?
1688 */ 1714 */
1689 int core_visible; 1715 int core_visible;
1716
1717 /**
1718 * Do we have the lastest value for @e last_dv_learn_monotime from
1719 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1720 */
1721 int dv_monotime_available;
1690}; 1722};
1691 1723
1692 1724
@@ -2886,7 +2918,20 @@ free_neighbour (struct Neighbour *neighbour)
2886 free_dv_route (dv); 2918 free_dv_route (dv);
2887 } 2919 }
2888 if (NULL != neighbour->reassembly_timeout_task) 2920 if (NULL != neighbour->reassembly_timeout_task)
2921 {
2889 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task); 2922 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2923 neighbour->reassembly_timeout_task = NULL;
2924 }
2925 if (NULL != neighbour->get)
2926 {
2927 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2928 neighbour->get = NULL;
2929 }
2930 if (NULL != neighbour->sc)
2931 {
2932 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2933 neighbour->sc = NULL;
2934 }
2890 GNUNET_free (neighbour); 2935 GNUNET_free (neighbour);
2891} 2936}
2892 2937
@@ -6004,6 +6049,7 @@ forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6004/** 6049/**
6005 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR 6050 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6006 * 6051 *
6052 * @param sender_monotonic_time monotonic time of the initiator
6007 * @param init the signer 6053 * @param init the signer
6008 * @param challenge the challenge that was signed 6054 * @param challenge the challenge that was signed
6009 * @param init_sig signature presumably by @a init 6055 * @param init_sig signature presumably by @a init
@@ -6011,6 +6057,7 @@ forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6011 */ 6057 */
6012static int 6058static int
6013validate_dv_initiator_signature ( 6059validate_dv_initiator_signature (
6060 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6014 const struct GNUNET_PeerIdentity *init, 6061 const struct GNUNET_PeerIdentity *init,
6015 const struct ChallengeNonceP *challenge, 6062 const struct ChallengeNonceP *challenge,
6016 const struct GNUNET_CRYPTO_EddsaSignature *init_sig) 6063 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
@@ -6018,6 +6065,7 @@ validate_dv_initiator_signature (
6018 struct DvInitPS ip = {.purpose.purpose = htonl ( 6065 struct DvInitPS ip = {.purpose.purpose = htonl (
6019 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR), 6066 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6020 .purpose.size = htonl (sizeof (ip)), 6067 .purpose.size = htonl (sizeof (ip)),
6068 .monotonic_time = sender_monotonic_time,
6021 .challenge = *challenge}; 6069 .challenge = *challenge};
6022 6070
6023 if ( 6071 if (
@@ -6224,6 +6272,24 @@ calculate_fork_degree (unsigned int hops_taken,
6224 6272
6225 6273
6226/** 6274/**
6275 * Function called when peerstore is done storing a DV monotonic time.
6276 *
6277 * @param cls a `struct Neighbour`
6278 * @param success #GNUNET_YES if peerstore was successful
6279 */
6280static void
6281neighbour_store_dvmono_cb (void *cls, int success)
6282{
6283 struct Neighbour *n = cls;
6284
6285 n->sc = NULL;
6286 if (GNUNET_YES != success)
6287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6288 "Failed to store other peer's monotonic time in peerstore!\n");
6289}
6290
6291
6292/**
6227 * Communicator gave us a DV learn message. Process the request. 6293 * Communicator gave us a DV learn message. Process the request.
6228 * 6294 *
6229 * @param cls a `struct CommunicatorMessageContext` (must call 6295 * @param cls a `struct CommunicatorMessageContext` (must call
@@ -6242,6 +6308,7 @@ handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6242 int do_fwd; 6308 int do_fwd;
6243 int did_initiator; 6309 int did_initiator;
6244 struct GNUNET_TIME_Absolute in_time; 6310 struct GNUNET_TIME_Absolute in_time;
6311 struct Neighbour *n;
6245 6312
6246 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */ 6313 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6247 bi_history = ntohs (dvl->bidirectional); 6314 bi_history = ntohs (dvl->bidirectional);
@@ -6276,15 +6343,44 @@ handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6276 /* continue communicator here, everything else can happen asynchronous! */ 6343 /* continue communicator here, everything else can happen asynchronous! */
6277 finish_cmc_handling (cmc); 6344 finish_cmc_handling (cmc);
6278 6345
6279 /* OPTIMIZE-FIXME: Technically, we only need to bother checking 6346 n = lookup_neighbour (&dvl->initiator);
6280 the initiator signature if we send the message back to the initiator... 6347 if (NULL != n)
6281 */
6282 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
6283 &dvl->challenge,
6284 &dvl->init_sig))
6285 { 6348 {
6286 GNUNET_break_op (0); 6349 if ((n->dv_monotime_available == GNUNET_YES) &&
6287 return; 6350 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6351 n->last_dv_learn_monotime.abs_value_us))
6352 {
6353 GNUNET_STATISTICS_update (GST_stats,
6354 "# DV learn discarded due to time travel",
6355 1,
6356 GNUNET_NO);
6357 return;
6358 }
6359 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6360 &dvl->initiator,
6361 &dvl->challenge,
6362 &dvl->init_sig))
6363 {
6364 GNUNET_break_op (0);
6365 return;
6366 }
6367 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6368 if (GNUNET_YES == n->dv_monotime_available)
6369 {
6370 if (NULL != n->sc)
6371 GNUNET_PEERSTORE_store_cancel (n->sc);
6372 n->sc =
6373 GNUNET_PEERSTORE_store (peerstore,
6374 "transport",
6375 &dvl->initiator,
6376 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6377 &dvl->monotonic_time,
6378 sizeof (dvl->monotonic_time),
6379 GNUNET_TIME_UNIT_FOREVER_ABS,
6380 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6381 &neighbour_store_dvmono_cb,
6382 n);
6383 }
6288 } 6384 }
6289 // FIXME: asynchronously (!) verify hop-by-hop signatures! 6385 // FIXME: asynchronously (!) verify hop-by-hop signatures!
6290 // => if signature verification load too high, implement random drop 6386 // => if signature verification load too high, implement random drop
@@ -8057,10 +8153,13 @@ start_dv_learn (void *cls)
8057 dvl.num_hops = htons (0); 8153 dvl.num_hops = htons (0);
8058 dvl.bidirectional = htons (0); 8154 dvl.bidirectional = htons (0);
8059 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); 8155 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8156 dvl.monotonic_time =
8157 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8060 { 8158 {
8061 struct DvInitPS dvip = {.purpose.purpose = htonl ( 8159 struct DvInitPS dvip = {.purpose.purpose = htonl (
8062 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR), 8160 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8063 .purpose.size = htonl (sizeof (dvip)), 8161 .purpose.size = htonl (sizeof (dvip)),
8162 .monotonic_time = dvl.monotonic_time,
8064 .challenge = lle->challenge}; 8163 .challenge = lle->challenge};
8065 8164
8066 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, 8165 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
@@ -8122,6 +8221,44 @@ check_validation_request_pending (void *cls,
8122 8221
8123 8222
8124/** 8223/**
8224 * Function called with the monotonic time of a DV initiator
8225 * by PEERSTORE. Updates the time.
8226 *
8227 * @param cls a `struct Neighbour`
8228 * @param record the information found, NULL for the last call
8229 * @param emsg error message
8230 */
8231static void
8232neighbour_dv_monotime_cb (void *cls,
8233 const struct GNUNET_PEERSTORE_Record *record,
8234 const char *emsg)
8235{
8236 struct Neighbour *n = cls;
8237 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8238 struct GNUNET_TIME_Absolute mt;
8239
8240 (void) emsg;
8241 if (NULL == record)
8242 {
8243 /* we're done with #neighbour_dv_monotime_cb() invocations,
8244 continue normal processing */
8245 n->get = NULL;
8246 n->dv_monotime_available = GNUNET_YES;
8247 return;
8248 }
8249 if (sizeof (*mtbe) != record->value_size)
8250 {
8251 GNUNET_break (0);
8252 return;
8253 }
8254 mtbe = record->value;
8255 n->last_dv_learn_monotime =
8256 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8257 GNUNET_TIME_absolute_ntoh (*mtbe));
8258}
8259
8260
8261/**
8125 * New queue became available. Process the request. 8262 * New queue became available. Process the request.
8126 * 8263 *
8127 * @param cls the client 8264 * @param cls the client
@@ -8157,6 +8294,13 @@ handle_add_queue_message (void *cls,
8157 &neighbour->pid, 8294 &neighbour->pid,
8158 neighbour, 8295 neighbour,
8159 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 8296 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8297 neighbour->get =
8298 GNUNET_PEERSTORE_iterate (peerstore,
8299 "transport",
8300 &neighbour->pid,
8301 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8302 &neighbour_dv_monotime_cb,
8303 neighbour);
8160 } 8304 }
8161 addr_len = ntohs (aqm->header.size) - sizeof (*aqm); 8305 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8162 addr = (const char *) &aqm[1]; 8306 addr = (const char *) &aqm[1];