/*
This file is part of GNUnet.
- Copyright (C) 2013, 2017 GNUnet e.V.
+ Copyright (C) 2013, 2017, 2018 GNUnet e.V.
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
+ SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file cadet/gnunet-service-cadet_tunnels.c
*/
struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
+ /**
+ * Last ephemeral public key received from the other peer,
+ * for duplicate detection.
+ */
+ struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
+
/**
* Time when the current ratchet expires and a new one is triggered
* (if @e ratchet_allowed is #GNUNET_YES).
};
+/**
+ * Am I Alice or Betty (some call her Bob), or talking to myself?
+ *
+ * @param other the other peer
+ * @return #GNUNET_YES for Alice, #GNUNET_NO for Betty, #GNUNET_SYSERR if talking to myself
+ */
+static int
+alice_or_betty (const struct GNUNET_PeerIdentity *other)
+{
+ if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+ other))
+ return GNUNET_YES;
+ else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+ other))
+ return GNUNET_NO;
+ else
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+}
+
+
/**
* Connection @a ct is now unready, clear it's ready flag
* and move it from the ready DLL to the busy DLL.
struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
enum GNUNET_CADET_KX_Flags flags;
+ if (GNUNET_YES != alice_or_betty (GCP_get_id (t->destination)))
+ return; /* only Alice may send KX */
if ( (NULL == ct) ||
(GNUNET_NO == ct->is_ready) )
ct = get_ready_connection (t);
return;
}
cc = ct->cc;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending KX on %s via %s in state %s\n",
- GCT_2s (t),
- GCC_2s (cc),
- estate2s (t->estate));
env = GNUNET_MQ_msg (msg,
GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
msg->cid = *GCC_get_id (cc);
GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
&msg->ephemeral_key);
+#if DEBUG_KX
+ msg->ephemeral_key_XXX = ax->kx_0;
+ msg->private_key_XXX = *my_private_key;
+#endif
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending KX message to %s with ephemeral %s on CID %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->ephemeral_key),
+ GNUNET_sh2s (&msg->cid.connection_of_tunnel));
GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
&msg->ratchet_key);
mark_connection_unready (ct);
CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
GCC_transmit (cc,
env);
+ GNUNET_STATISTICS_update (stats,
+ "# KX transmitted",
+ 1,
+ GNUNET_NO);
}
}
t->kx_auth_requested = GNUNET_NO; /* clear flag */
cc = ct->cc;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending KX_AUTH on %s using %s\n",
- GCT_2s (t),
- GCC_2s (ct->cc));
-
env = GNUNET_MQ_msg (msg,
GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH);
flags = GNUNET_CADET_KX_FLAG_NONE;
&msg->kx.ephemeral_key);
GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
&msg->kx.ratchet_key);
+#if DEBUG_KX
+ msg->kx.ephemeral_key_XXX = ax->kx_0;
+ msg->kx.private_key_XXX = *my_private_key;
+ msg->r_ephemeral_key_XXX = ax->last_ephemeral;
+#endif
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending KX_AUTH message to %s with ephemeral %s on CID %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->kx.ephemeral_key),
+ GNUNET_sh2s (&msg->kx.cid.connection_of_tunnel));
+
/* Compute authenticator (this is the main difference to #send_kx()) */
GNUNET_CRYPTO_hash (&ax->RK,
sizeof (ax->RK),
&msg->auth);
-
/* Compute when to be triggered again; actual job will
be scheduled via #connection_ready_cb() */
t->kx_retry_delay
if (CADET_TUNNEL_KEY_OK != t->estate)
GCT_change_estate (t,
CADET_TUNNEL_KEY_AX_AUTH_SENT);
-
GCC_transmit (cc,
env);
+ GNUNET_STATISTICS_update (stats,
+ "# KX_AUTH transmitted",
+ 1,
+ GNUNET_NO);
}
const char salt[] = "CADET Axolotl salt";
int am_I_alice;
- if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
- pid))
- am_I_alice = GNUNET_YES;
- else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
- pid))
- am_I_alice = GNUNET_NO;
- else
+ if (GNUNET_SYSERR == (am_I_alice = alice_or_betty (pid)))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
-
if (0 == memcmp (&ax->DHRr,
ratchet_key,
sizeof (*ratchet_key)))
{
+ GNUNET_STATISTICS_update (stats,
+ "# Ratchet key already known",
+ 1,
+ GNUNET_NO);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Ratchet key already known. Ignoring KX.\n");
return GNUNET_NO;
}
ax->DHRr = *ratchet_key;
-
+ ax->last_ephemeral = *ephemeral_key;
/* ECDH A B0 */
if (GNUNET_YES == am_I_alice)
{
- GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */
- ephemeral_key, /* B0 */
+ GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* a */
+ ephemeral_key, /* B0 */
&key_material[0]);
}
else
{
- GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* B0 */
- &pid->public_key, /* A */
+ GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* b0 */
+ &pid->public_key, /* A */
&key_material[0]);
}
-
/* ECDH A0 B */
if (GNUNET_YES == am_I_alice)
{
- GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* A0 */
- &pid->public_key, /* B */
+ GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* a0 */
+ &pid->public_key, /* B */
&key_material[1]);
}
else
{
- GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */
- ephemeral_key, /* B0 */
+ GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* b */
+ ephemeral_key, /* A0 */
&key_material[1]);
-
-
}
/* ECDH A0 B0 */
- /* (This is the triple-DH, we could probably safely skip this,
- as A0/B0 are already in the key material.) */
- GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0, /* A0 or B0 */
- ephemeral_key, /* B0 or A0 */
+ GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0, /* a0 or b0 */
+ ephemeral_key, /* B0 or A0 */
&key_material[2]);
-
/* KDF */
GNUNET_CRYPTO_kdf (keys, sizeof (keys),
salt, sizeof (salt),
sizeof (ax->RK)))
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Root key of handshake already known. Ignoring KX.\n");
+ "Root key already known. Ignoring KX.\n");
+ GNUNET_STATISTICS_update (stats,
+ "# Root key already known",
+ 1,
+ GNUNET_NO);
return GNUNET_NO;
}
GCT_2s (t),
estate2s (t->estate));
switch (t->estate)
- {
- case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
- case CADET_TUNNEL_KEY_AX_SENT: /* trying again */
- send_kx (t,
- NULL,
- &t->ax);
- break;
- case CADET_TUNNEL_KEY_AX_RECV:
- case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
- /* We are responding, so only require reply
- if WE have a channel waiting. */
- if (NULL != t->unverified_ax)
- {
- /* Send AX_AUTH so we might get this one verified */
- ax = t->unverified_ax;
- }
- else
- {
- /* How can this be? */
- GNUNET_break (0);
- ax = &t->ax;
- }
- send_kx_auth (t,
- NULL,
- ax,
- (0 == GCT_count_channels (t))
- ? GNUNET_NO
- : GNUNET_YES);
- break;
- case CADET_TUNNEL_KEY_AX_AUTH_SENT:
- /* We are responding, so only require reply
- if WE have a channel waiting. */
- if (NULL != t->unverified_ax)
- {
- /* Send AX_AUTH so we might get this one verified */
- ax = t->unverified_ax;
- }
- else
- {
- /* How can this be? */
- GNUNET_break (0);
- ax = &t->ax;
- }
- send_kx_auth (t,
- NULL,
- ax,
- (0 == GCT_count_channels (t))
- ? GNUNET_NO
- : GNUNET_YES);
- break;
- case CADET_TUNNEL_KEY_OK:
- /* Must have been the *other* peer asking us to
- respond with a KX_AUTH. */
- if (NULL != t->unverified_ax)
- {
- /* Sending AX_AUTH in response to AX so we might get this one verified */
- ax = t->unverified_ax;
- }
- else
{
- /* Sending AX_AUTH in response to AX_AUTH */
- ax = &t->ax;
+ case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
+ case CADET_TUNNEL_KEY_AX_SENT: /* trying again */
+ send_kx (t,
+ NULL,
+ &t->ax);
+ break;
+ case CADET_TUNNEL_KEY_AX_RECV:
+ case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+ /* We are responding, so only require reply
+ if WE have a channel waiting. */
+ if (NULL != t->unverified_ax)
+ {
+ /* Send AX_AUTH so we might get this one verified */
+ ax = t->unverified_ax;
+ }
+ else
+ {
+ /* How can this be? */
+ GNUNET_break (0);
+ ax = &t->ax;
+ }
+ send_kx_auth (t,
+ NULL,
+ ax,
+ (0 == GCT_count_channels (t))
+ ? GNUNET_NO
+ : GNUNET_YES);
+ break;
+ case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+ /* We are responding, so only require reply
+ if WE have a channel waiting. */
+ if (NULL != t->unverified_ax)
+ {
+ /* Send AX_AUTH so we might get this one verified */
+ ax = t->unverified_ax;
+ }
+ else
+ {
+ /* How can this be? */
+ GNUNET_break (0);
+ ax = &t->ax;
+ }
+ send_kx_auth (t,
+ NULL,
+ ax,
+ (0 == GCT_count_channels (t))
+ ? GNUNET_NO
+ : GNUNET_YES);
+ break;
+ case CADET_TUNNEL_KEY_OK:
+ /* Must have been the *other* peer asking us to
+ respond with a KX_AUTH. */
+ if (NULL != t->unverified_ax)
+ {
+ /* Sending AX_AUTH in response to AX so we might get this one verified */
+ ax = t->unverified_ax;
+ }
+ else
+ {
+ /* Sending AX_AUTH in response to AX_AUTH */
+ ax = &t->ax;
+ }
+ send_kx_auth (t,
+ NULL,
+ ax,
+ GNUNET_NO);
+ break;
}
- send_kx_auth (t,
- NULL,
- ax,
- GNUNET_NO);
- break;
- }
}
const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
{
struct CadetTunnel *t = ct->t;
- struct CadetTunnelAxolotl *ax;
int ret;
- if (0 ==
- memcmp (&t->ax.DHRr,
- &msg->ratchet_key,
- sizeof (msg->ratchet_key)))
+ GNUNET_STATISTICS_update (stats,
+ "# KX received",
+ 1,
+ GNUNET_NO);
+ if (GNUNET_YES ==
+ alice_or_betty (GCP_get_id (t->destination)))
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got duplicate KX. Firing back KX_AUTH.\n");
- send_kx_auth (t,
- ct,
- &t->ax,
- GNUNET_NO);
+ /* Betty/Bob is not allowed to send KX! */
+ GNUNET_break_op (0);
return;
}
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received KX message from %s with ephemeral %s from %s on connection %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->ephemeral_key),
+ GNUNET_i2s (GCP_get_id (t->destination)),
+ GCC_2s (ct->cc));
+#if 1
+ if ( (0 ==
+ memcmp (&t->ax.DHRr,
+ &msg->ratchet_key,
+ sizeof (msg->ratchet_key))) &&
+ (0 ==
+ memcmp (&t->ax.last_ephemeral,
+ &msg->ephemeral_key,
+ sizeof (msg->ephemeral_key))) )
+ {
+ GNUNET_STATISTICS_update (stats,
+ "# Duplicate KX received",
+ 1,
+ GNUNET_NO);
+ send_kx_auth (t,
+ ct,
+ &t->ax,
+ GNUNET_NO);
+ return;
+ }
+#endif
/* We only keep ONE unverified KX around, so if there is an existing one,
clean it up. */
if (NULL != t->unverified_ax)
{
- if (0 ==
- memcmp (&t->unverified_ax->DHRr,
- &msg->ratchet_key,
- sizeof (msg->ratchet_key)))
+ if ( (0 ==
+ memcmp (&t->unverified_ax->DHRr,
+ &msg->ratchet_key,
+ sizeof (msg->ratchet_key))) &&
+ (0 ==
+ memcmp (&t->unverified_ax->last_ephemeral,
+ &msg->ephemeral_key,
+ sizeof (msg->ephemeral_key))) )
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
- GCT_2s (t));
+ GNUNET_STATISTICS_update (stats,
+ "# Duplicate unverified KX received",
+ 1,
+ GNUNET_NO);
+#if 1
send_kx_auth (t,
ct,
t->unverified_ax,
GNUNET_NO);
return;
+#endif
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Dropping old unverified KX state. Got a fresh KX for %s.\n",
- GCT_2s (t));
+ "Dropping old unverified KX state.\n");
+ GNUNET_STATISTICS_update (stats,
+ "# Unverified KX dropped for fresh KX",
+ 1,
+ GNUNET_NO);
+ GNUNET_break (NULL == t->unverified_ax->skipped_head);
memset (t->unverified_ax,
0,
sizeof (struct CadetTunnelAxolotl));
- t->unverified_ax->DHRs = t->ax.DHRs;
- t->unverified_ax->kx_0 = t->ax.kx_0;
}
else
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating fresh unverified KX for %s.\n",
+ "Creating fresh unverified KX for %s\n",
GCT_2s (t));
+ GNUNET_STATISTICS_update (stats,
+ "# Fresh KX setup",
+ 1,
+ GNUNET_NO);
t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
- t->unverified_ax->DHRs = t->ax.DHRs;
- t->unverified_ax->kx_0 = t->ax.kx_0;
}
/* Set as the 'current' RK/DHRr the one we are currently using,
so that the duplicate-detection logic of
#update_ax_by_kx can work. */
t->unverified_ax->RK = t->ax.RK;
t->unverified_ax->DHRr = t->ax.DHRr;
+ t->unverified_ax->DHRs = t->ax.DHRs;
+ t->unverified_ax->kx_0 = t->ax.kx_0;
t->unverified_attempts = 0;
- ax = t->unverified_ax;
/* Update 'ax' by the new key material */
- ret = update_ax_by_kx (ax,
+ ret = update_ax_by_kx (t->unverified_ax,
GCP_get_id (t->destination),
&msg->ephemeral_key,
&msg->ratchet_key);
GNUNET_break (GNUNET_SYSERR != ret);
if (GNUNET_OK != ret)
+ {
+ GNUNET_STATISTICS_update (stats,
+ "# Useless KX",
+ 1,
+ GNUNET_NO);
return; /* duplicate KX, nothing to do */
-
+ }
/* move ahead in our state machine */
if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
GCT_change_estate (t,
}
+#if DEBUG_KX
+static void
+check_ee (const struct GNUNET_CRYPTO_EcdhePrivateKey *e1,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *e2)
+{
+ struct GNUNET_CRYPTO_EcdhePublicKey p1;
+ struct GNUNET_CRYPTO_EcdhePublicKey p2;
+ struct GNUNET_HashCode hc1;
+ struct GNUNET_HashCode hc2;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (e1,
+ &p1);
+ GNUNET_CRYPTO_ecdhe_key_get_public (e2,
+ &p2);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecc_ecdh (e1,
+ &p2,
+ &hc1));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecc_ecdh (e2,
+ &p1,
+ &hc2));
+ GNUNET_break (0 == memcmp (&hc1,
+ &hc2,
+ sizeof (hc1)));
+}
+
+
+static void
+check_ed (const struct GNUNET_CRYPTO_EcdhePrivateKey *e1,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *e2)
+{
+ struct GNUNET_CRYPTO_EcdhePublicKey p1;
+ struct GNUNET_CRYPTO_EddsaPublicKey p2;
+ struct GNUNET_HashCode hc1;
+ struct GNUNET_HashCode hc2;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (e1,
+ &p1);
+ GNUNET_CRYPTO_eddsa_key_get_public (e2,
+ &p2);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecdh_eddsa (e1,
+ &p2,
+ &hc1));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_ecdh (e2,
+ &p1,
+ &hc2));
+ GNUNET_break (0 == memcmp (&hc1,
+ &hc2,
+ sizeof (hc1)));
+}
+
+
+static void
+test_crypto_bug (const struct GNUNET_CRYPTO_EcdhePrivateKey *e1,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *e2,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *d1,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *d2)
+{
+ check_ee (e1, e2);
+ check_ed (e1, d2);
+ check_ed (e2, d1);
+}
+
+#endif
+
+
/**
* Handle KX_AUTH message.
*
struct GNUNET_HashCode kx_auth;
int ret;
+ GNUNET_STATISTICS_update (stats,
+ "# KX_AUTH received",
+ 1,
+ GNUNET_NO);
if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
(CADET_TUNNEL_KEY_AX_RECV == t->estate) )
{
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Handling KX_AUTH message for %s\n",
- GCT_2s (t));
-
+ "Handling KX_AUTH message from %s with ephemeral %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->kx.ephemeral_key));
/* We do everything in ax_tmp until we've checked the authentication
so we don't clobber anything we care about by accident. */
ax_tmp = t->ax;
"# KX_AUTH not using our last KX received (auth failure)",
1,
GNUNET_NO);
- send_kx (t,
- ct,
- &t->ax);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "KX AUTH mismatch!\n");
+#if DEBUG_KX
+ {
+ struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (&ax_tmp.kx_0,
+ &ephemeral_key);
+ if (0 != memcmp (&ephemeral_key,
+ &msg->r_ephemeral_key_XXX,
+ sizeof (ephemeral_key)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "My ephemeral is %s!\n",
+ GNUNET_e2s (&ephemeral_key));
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Response is for ephemeral %s!\n",
+ GNUNET_e2s (&msg->r_ephemeral_key_XXX));
+ }
+ else
+ {
+ test_crypto_bug (&ax_tmp.kx_0,
+ &msg->kx.ephemeral_key_XXX,
+ my_private_key,
+ &msg->kx.private_key_XXX);
+ }
+ }
+#endif
+ if (NULL == t->kx_task)
+ t->kx_task
+ = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+ &retry_kx,
+ t);
return;
}
/* Yep, we're good. */
Nothing to do here. */
break;
}
+ if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->kx.flags)))
+ {
+ send_kx_auth (t,
+ NULL,
+ &t->ax,
+ GNUNET_NO);
+ }
}
{
case CADET_TUNNEL_KEY_UNINITIALIZED:
/* Do not begin KX if WE have no channels waiting! */
- if (0 == GCT_count_channels (t))
- return;
+ if (0 != GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt).rel_value_us)
+ return; /* wait for timeout before retrying */
/* We are uninitialized, just transmit immediately,
without undue delay. */
if (NULL != t->kx_task)
send_kx (t,
ct,
&t->ax);
+ if ( (0 ==
+ GCT_count_channels (t)) &&
+ (NULL == t->destroy_task) )
+ {
+ t->destroy_task
+ = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+ &destroy_tunnel,
+ t);
+ }
break;
case CADET_TUNNEL_KEY_AX_RECV:
case CADET_TUNNEL_KEY_AX_SENT:
case CADET_TUNNEL_KEY_OK:
if (GNUNET_YES == t->kx_auth_requested)
{
+ if (0 != GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt).rel_value_us)
+ return; /* wait for timeout */
if (NULL != t->kx_task)
{
GNUNET_SCHEDULER_cancel (t->kx_task);
{
struct EvaluationSummary *es = cls;
struct CadetConnection *cc = ct->cc;
- struct CadetPeerPath *ps = GCC_get_path (cc);
+ unsigned int ct_length;
+ struct CadetPeerPath *ps;
const struct CadetConnectionMetrics *metrics;
GNUNET_CONTAINER_HeapCostType ct_desirability;
struct GNUNET_TIME_Relative uptime;
struct GNUNET_TIME_Relative last_use;
- uint32_t ct_length;
double score;
double success_rate;
+ ps = GCC_get_path (cc,
+ &ct_length);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Evaluating path %s of existing %s\n",
+ GCPP_2s (ps),
+ GCC_2s (cc));
if (ps == es->path)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
es->duplicate = GNUNET_YES;
return;
}
+ if (NULL != es->path)
+ {
+ int duplicate = GNUNET_YES;
+
+ for (unsigned int i=0;i<ct_length;i++)
+ {
+ GNUNET_assert (GCPP_get_length (es->path) > i);
+ if (GCPP_get_peer_at_offset (es->path,
+ i) !=
+ GCPP_get_peer_at_offset (ps,
+ i))
+ {
+ duplicate = GNUNET_NO;
+ break;
+ }
+ }
+ if (GNUNET_YES == duplicate)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring overlapping path %s.\n",
+ GCPP_2s (es->path));
+ es->duplicate = GNUNET_YES;
+ return;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Known path %s differs from proposed path\n",
+ GCPP_2s (ps));
+ }
+ }
+
ct_desirability = GCPP_get_desirability (ps);
- ct_length = GCPP_get_length (ps);
metrics = GCC_get_metrics (cc);
uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
struct CadetTConnection *ct;
GNUNET_assert (off < GCPP_get_length (path));
+ GNUNET_assert (GCPP_get_peer_at_offset (path,
+ off) == t->destination);
es.min_length = UINT_MAX;
es.max_length = 0;
es.max_desire = 0;
es.worst = NULL;
/* Compute evaluation summary over existing connections. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Evaluating proposed path %s for target %s\n",
+ GCPP_2s (path),
+ GCT_2s (t));
+ /* FIXME: suspect this does not ACTUALLY iterate
+ over all existing paths, otherwise dup detection
+ should work!!! */
GCT_iterate_connections (t,
&evaluate_connection,
&es);
unsigned int off)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Considering %s for %s\n",
+ "Considering %s for %s (offset %u)\n",
GCPP_2s (p),
- GCT_2s (t));
+ GCT_2s (t),
+ off);
(void) consider_path_cb (t,
p,
off);
*
* @param cls the `struct CadetTunnel` that got the message
* @param msg the message
- * @return #GNUNET_OK (continue to process)
+ * @return #GNUNET_OK on success (always)
+ * #GNUNET_NO to stop further processing (no error)
+ * #GNUNET_SYSERR to stop further processing with error
*/
static int
handle_decrypted (void *cls,