aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-tng.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-04-21 14:49:26 +0200
committerChristian Grothoff <christian@grothoff.org>2019-04-21 14:49:26 +0200
commitfe3cc0e1a6f83c6ba4e0e1ec1185f1173ff16570 (patch)
treed3ab1e64f4e7643f059205e8dbf2cbc08295afbe /src/transport/gnunet-service-tng.c
parent196435205b803f01976560037c69553ac0e8e307 (diff)
downloadgnunet-fe3cc0e1a6f83c6ba4e0e1ec1185f1173ff16570.tar.gz
gnunet-fe3cc0e1a6f83c6ba4e0e1ec1185f1173ff16570.zip
finish backchannel message delivery
Diffstat (limited to 'src/transport/gnunet-service-tng.c')
-rw-r--r--src/transport/gnunet-service-tng.c412
1 files changed, 400 insertions, 12 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
index 56ba70b9a..4dc3a137d 100644
--- a/src/transport/gnunet-service-tng.c
+++ b/src/transport/gnunet-service-tng.c
@@ -24,8 +24,6 @@
24 * 24 *
25 * TODO: 25 * TODO:
26 * Implement next: 26 * Implement next:
27 * - complete backchannel signature verification and
28 * forwarding of backchannel messages to communicators!
29 * - track RTT, distance, loss, etc. => requires extra data structures! 27 * - track RTT, distance, loss, etc. => requires extra data structures!
30 * - proper use/initialization of timestamps in messages exchanged 28 * - proper use/initialization of timestamps in messages exchanged
31 * during DV learning 29 * during DV learning
@@ -153,6 +151,13 @@
153 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) 151 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
154 152
155/** 153/**
154 * How long do we cache backchannel (struct Backtalker) information
155 * after a backchannel goes inactive?
156 */
157#define BACKCHANNEL_INACTIVITY_TIMEOUT \
158 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
159
160/**
156 * How long before paths expire would we like to (re)discover DV paths? Should 161 * How long before paths expire would we like to (re)discover DV paths? Should
157 * be below #DV_PATH_VALIDITY_TIMEOUT. 162 * be below #DV_PATH_VALIDITY_TIMEOUT.
158 */ 163 */
@@ -289,7 +294,7 @@ struct TransportBackchannelEncapsulationMessage
289/** 294/**
290 * Body by which a peer confirms that it is using an ephemeral key. 295 * Body by which a peer confirms that it is using an ephemeral key.
291 */ 296 */
292struct EphemeralConfirmation 297struct EphemeralConfirmationPS
293{ 298{
294 299
295 /** 300 /**
@@ -1965,6 +1970,65 @@ struct ValidationState
1965 1970
1966 1971
1967/** 1972/**
1973 * A Backtalker is a peer sending us backchannel messages. We use this
1974 * struct to detect monotonic time violations, cache ephemeral key
1975 * material (to avoid repeatedly checking signatures), and to synchronize
1976 * monotonic time with the PEERSTORE.
1977 */
1978struct Backtalker
1979{
1980 /**
1981 * Peer this is about.
1982 */
1983 struct GNUNET_PeerIdentity pid;
1984
1985 /**
1986 * Last (valid) monotonic time received from this sender.
1987 */
1988 struct GNUNET_TIME_Absolute monotonic_time;
1989
1990 /**
1991 * When will this entry time out?
1992 */
1993 struct GNUNET_TIME_Absolute timeout;
1994
1995 /**
1996 * Last (valid) ephemeral key received from this sender.
1997 */
1998 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
1999
2000 /**
2001 * Task associated with this backtalker. Can be for timeout,
2002 * or other asynchronous operations.
2003 */
2004 struct GNUNET_SCHEDULER_Task *task;
2005
2006 /**
2007 * Communicator context waiting on this backchannel's @e get, or NULL.
2008 */
2009 struct CommunicatorMessageContext *cmc;
2010
2011 /**
2012 * Handle for an operation to fetch @e monotonic_time information from the
2013 * PEERSTORE, or NULL.
2014 */
2015 struct GNUNET_PEERSTORE_IterateContext *get;
2016
2017 /**
2018 * Handle to a PEERSTORE store operation for this @e pid's @e
2019 * monotonic_time. NULL if no PEERSTORE operation is pending.
2020 */
2021 struct GNUNET_PEERSTORE_StoreContext *sc;
2022
2023 /**
2024 * Number of bytes of the original message body that follows after this
2025 * struct.
2026 */
2027 size_t body_size;
2028};
2029
2030
2031/**
1968 * Head of linked list of all clients to this service. 2032 * Head of linked list of all clients to this service.
1969 */ 2033 */
1970static struct TransportClient *clients_head; 2034static struct TransportClient *clients_head;
@@ -2001,6 +2065,12 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2001static struct GNUNET_CONTAINER_MultiPeerMap *neighbours; 2065static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2002 2066
2003/** 2067/**
2068 * Map from PIDs to `struct Backtalker` entries. A peer is
2069 * a backtalker if it recently send us backchannel messages.
2070 */
2071static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2072
2073/**
2004 * Map from PIDs to `struct DistanceVector` entries describing 2074 * Map from PIDs to `struct DistanceVector` entries describing
2005 * known paths to the peer. 2075 * known paths to the peer.
2006 */ 2076 */
@@ -3195,7 +3265,7 @@ lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3195 struct GNUNET_TIME_Absolute *ephemeral_validity) 3265 struct GNUNET_TIME_Absolute *ephemeral_validity)
3196{ 3266{
3197 struct EphemeralCacheEntry *ece; 3267 struct EphemeralCacheEntry *ece;
3198 struct EphemeralConfirmation ec; 3268 struct EphemeralConfirmationPS ec;
3199 3269
3200 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid); 3270 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3201 if ((NULL != ece) && 3271 if ((NULL != ece) &&
@@ -4570,6 +4640,254 @@ check_backchannel_encapsulation (
4570 4640
4571 4641
4572/** 4642/**
4643 * We received the plaintext @a msg from backtalker @a b. Forward
4644 * it to the respective communicator.
4645 *
4646 * @param b a backtalker
4647 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
4648 * followed by the target name of the communicator
4649 * @param msg_size number of bytes in @a msg
4650 */
4651static void
4652forward_backchannel_payload (struct Backtalker *b,
4653 const void *msg,
4654 size_t msg_size)
4655{
4656 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
4657 struct GNUNET_MQ_Envelope *env;
4658 struct TransportClient *tc;
4659 const struct GNUNET_MessageHeader *mh;
4660 const char *target_communicator;
4661 uint16_t mhs;
4662
4663 /* Determine target_communicator and check @a msg is well-formed */
4664 mh = msg;
4665 mhs = ntohs (mh->size);
4666 if (mhs <= msg_size)
4667 {
4668 GNUNET_break_op (0);
4669 return;
4670 }
4671 target_communicator = &((const char *) msg)[ntohs (mh->size)];
4672 if ('\0' != target_communicator[msg_size - mhs - 1])
4673 {
4674 GNUNET_break_op (0);
4675 return;
4676 }
4677 /* Find client providing this communicator */
4678 for (tc = clients_head; NULL != tc; tc = tc->next)
4679 if ((CT_COMMUNICATOR == tc->type) &&
4680 (0 ==
4681 strcmp (tc->details.communicator.address_prefix, target_communicator)))
4682 break;
4683 if (NULL == tc)
4684 {
4685 char *stastr;
4686
4687 GNUNET_asprintf (
4688 &stastr,
4689 "# Backchannel message dropped: target communicator `%s' unknown",
4690 target_communicator);
4691 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
4692 GNUNET_free (stastr);
4693 return;
4694 }
4695 /* Finally, deliver backchannel message to communicator */
4696 env = GNUNET_MQ_msg_extra (
4697 cbi,
4698 msg_size,
4699 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
4700 cbi->pid = b->pid;
4701 memcpy (&cbi[1], msg, msg_size);
4702 GNUNET_MQ_send (tc->mq, env);
4703}
4704
4705
4706/**
4707 * Free data structures associated with @a b.
4708 *
4709 * @param b data structure to release
4710 */
4711static void
4712free_backtalker (struct Backtalker *b)
4713{
4714 if (NULL != b->get)
4715 {
4716 GNUNET_PEERSTORE_iterate_cancel (b->get);
4717 b->get = NULL;
4718 GNUNET_assert (NULL != b->cmc);
4719 finish_cmc_handling (b->cmc);
4720 b->cmc = NULL;
4721 }
4722 if (NULL != b->task)
4723 {
4724 GNUNET_SCHEDULER_cancel (b->task);
4725 b->task = NULL;
4726 }
4727 if (NULL != b->sc)
4728 {
4729 GNUNET_PEERSTORE_store_cancel (b->sc);
4730 b->sc = NULL;
4731 }
4732 GNUNET_assert (
4733 GNUNET_YES ==
4734 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
4735 GNUNET_free (b);
4736}
4737
4738
4739/**
4740 * Callback to free backtalker records.
4741 *
4742 * @param cls NULL
4743 * @param pid unused
4744 * @param value a `struct Backtalker`
4745 * @return #GNUNET_OK (always)
4746 */
4747static int
4748free_backtalker_cb (void *cls,
4749 const struct GNUNET_PeerIdentity *pid,
4750 void *value)
4751{
4752 struct Backtalker *b = value;
4753
4754 (void) cls;
4755 (void) pid;
4756 free_backtalker (b);
4757 return GNUNET_OK;
4758}
4759
4760
4761/**
4762 * Function called when it is time to clean up a backtalker.
4763 *
4764 * @param cls a `struct Backtalker`
4765 */
4766static void
4767backtalker_timeout_cb (void *cls)
4768{
4769 struct Backtalker *b = cls;
4770
4771 b->task = NULL;
4772 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
4773 {
4774 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
4775 return;
4776 }
4777 GNUNET_assert (NULL == b->sc);
4778 free_backtalker (b);
4779}
4780
4781
4782/**
4783 * Function called with the monotonic time of a backtalker
4784 * by PEERSTORE. Updates the time and continues processing.
4785 *
4786 * @param cls a `struct Backtalker`
4787 * @param record the information found, NULL for the last call
4788 * @param emsg error message
4789 */
4790static void
4791backtalker_monotime_cb (void *cls,
4792 const struct GNUNET_PEERSTORE_Record *record,
4793 const char *emsg)
4794{
4795 struct Backtalker *b = cls;
4796 struct GNUNET_TIME_AbsoluteNBO *mtbe;
4797 struct GNUNET_TIME_Absolute mt;
4798
4799 (void) emsg;
4800 if (NULL == record)
4801 {
4802 /* we're done with #backtalker_monotime_cb() invocations,
4803 continue normal processing */
4804 b->get = NULL;
4805 GNUNET_assert (NULL != b->cmc);
4806 finish_cmc_handling (b->cmc);
4807 b->cmc = NULL;
4808 if (0 != b->body_size)
4809 forward_backchannel_payload (b, &b[1], b->body_size);
4810 return;
4811 }
4812 if (sizeof (*mtbe) != record->value_size)
4813 {
4814 GNUNET_break (0);
4815 return;
4816 }
4817 mtbe = record->value;
4818 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
4819 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
4820 {
4821 GNUNET_STATISTICS_update (
4822 GST_stats,
4823 "# Backchannel messages dropped: monotonic time not increasing",
4824 1,
4825 GNUNET_NO);
4826 b->monotonic_time = mt;
4827 /* Setting body_size to 0 prevents call to #forward_backchannel_payload() */
4828 b->body_size = 0;
4829 return;
4830 }
4831}
4832
4833
4834/**
4835 * Function called by PEERSTORE when the store operation of
4836 * a backtalker's monotonic time is complete.
4837 *
4838 * @param cls the `struct Backtalker`
4839 * @param success #GNUNET_OK on success
4840 */
4841static void
4842backtalker_monotime_store_cb (void *cls, int success)
4843{
4844 struct Backtalker *b = cls;
4845
4846 if (GNUNET_OK != success)
4847 {
4848 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4849 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
4850 }
4851 b->sc = NULL;
4852 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
4853}
4854
4855
4856/**
4857 * The backtalker @a b monotonic time changed. Update PEERSTORE.
4858 *
4859 * @param b a backtalker with updated monotonic time
4860 */
4861static void
4862update_backtalker_monotime (struct Backtalker *b)
4863{
4864 struct GNUNET_TIME_AbsoluteNBO mtbe;
4865
4866 if (NULL != b->sc)
4867 {
4868 GNUNET_PEERSTORE_store_cancel (b->sc);
4869 b->sc = NULL;
4870 }
4871 else
4872 {
4873 GNUNET_SCHEDULER_cancel (b->task);
4874 b->task = NULL;
4875 }
4876 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
4877 b->sc = GNUNET_PEERSTORE_store (peerstore,
4878 "transport",
4879 &b->pid,
4880 "transport-backchannel-monotonic-time",
4881 &mtbe,
4882 sizeof (mtbe),
4883 GNUNET_TIME_UNIT_FOREVER_ABS,
4884 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
4885 &backtalker_monotime_store_cb,
4886 b);
4887}
4888
4889
4890/**
4573 * Communicator gave us a backchannel encapsulation. Process the request. 4891 * Communicator gave us a backchannel encapsulation. Process the request.
4574 * (We are not the origin of the backchannel here, the communicator simply 4892 * (We are not the origin of the backchannel here, the communicator simply
4575 * received a backchannel message and we are expected to forward it.) 4893 * received a backchannel message and we are expected to forward it.)
@@ -4611,6 +4929,8 @@ handle_backchannel_encapsulation (
4611 } 4929 }
4612 /* begin actual decryption */ 4930 /* begin actual decryption */
4613 { 4931 {
4932 struct Backtalker *b;
4933 struct GNUNET_TIME_Absolute monotime;
4614 struct TransportBackchannelRequestPayload ppay; 4934 struct TransportBackchannelRequestPayload ppay;
4615 char body[hdr_len - sizeof (ppay)]; 4935 char body[hdr_len - sizeof (ppay)];
4616 4936
@@ -4619,15 +4939,77 @@ handle_backchannel_encapsulation (
4619 bc_decrypt (&key, &ppay, hdr, sizeof (ppay)); 4939 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4620 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay)); 4940 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4621 bc_key_clean (&key); 4941 bc_key_clean (&key);
4622 // FIXME: verify signatures in ppay! 4942 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
4623 // => check if ephemeral key is known & valid, if not 4943 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
4624 // => verify sig, cache ephemeral key 4944 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
4625 // => update monotonic_time of sender for replay detection 4945 {
4626 4946 GNUNET_STATISTICS_update (
4627 // FIXME: forward to specified communicator! 4947 GST_stats,
4628 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING) 4948 "# Backchannel messages dropped: monotonic time not increasing",
4949 1,
4950 GNUNET_NO);
4951 finish_cmc_handling (cmc);
4952 return;
4953 }
4954 if ((NULL == b) ||
4955 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
4956 {
4957 /* Check signature */
4958 struct EphemeralConfirmationPS ec;
4959
4960 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4961 ec.purpose.size = htonl (sizeof (ec));
4962 ec.target = GST_my_identity;
4963 ec.ephemeral_key = be->ephemeral_key;
4964 if (
4965 GNUNET_OK !=
4966 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
4967 &ec.purpose,
4968 &ppay.sender_sig,
4969 &ppay.sender.public_key))
4970 {
4971 /* Signature invalid, disard! */
4972 GNUNET_break_op (0);
4973 finish_cmc_handling (cmc);
4974 return;
4975 }
4976 }
4977 if (NULL != b)
4978 {
4979 /* update key cache and mono time */
4980 b->last_ephemeral = be->ephemeral_key;
4981 b->monotonic_time = monotime;
4982 update_backtalker_monotime (b);
4983 forward_backchannel_payload (b, body, sizeof (body));
4984 b->timeout =
4985 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
4986 finish_cmc_handling (cmc);
4987 return;
4988 }
4989 /* setup data structure to cache signature AND check
4990 monotonic time with PEERSTORE before forwarding backchannel payload */
4991 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
4992 b->pid = ppay.sender;
4993 b->body_size = sizeof (body);
4994 memcpy (&b[1], body, sizeof (body));
4995 GNUNET_assert (GNUNET_YES ==
4996 GNUNET_CONTAINER_multipeermap_put (
4997 backtalkers,
4998 &b->pid,
4999 b,
5000 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5001 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5002 b->cmc = cmc;
5003 b->timeout =
5004 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5005 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5006 b->get = GNUNET_PEERSTORE_iterate (peerstore,
5007 "transport",
5008 &b->pid,
5009 "transport-backchannel-monotonic-time",
5010 &backtalker_monotime_cb,
5011 b);
4629 } 5012 }
4630 finish_cmc_handling (cmc);
4631} 5013}
4632 5014
4633 5015
@@ -7453,6 +7835,11 @@ do_shutdown (void *cls)
7453 } 7835 }
7454 GNUNET_CONTAINER_multipeermap_destroy (neighbours); 7836 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7455 neighbours = NULL; 7837 neighbours = NULL;
7838 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
7839 &free_backtalker_cb,
7840 NULL);
7841 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
7842 backtalkers = NULL;
7456 GNUNET_CONTAINER_multipeermap_iterate (validation_map, 7843 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7457 &free_validation_state_cb, 7844 &free_validation_state_cb,
7458 NULL); 7845 NULL);
@@ -7496,6 +7883,7 @@ run (void *cls,
7496 (void) service; 7883 (void) service;
7497 /* setup globals */ 7884 /* setup globals */
7498 GST_cfg = c; 7885 GST_cfg = c;
7886 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7499 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES); 7887 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7500 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES); 7888 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7501 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES); 7889 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);