uint32_t opt GNUNET_PACKED;
/**
- * Destination port.
+ * Hash of destination port and listener.
*/
- struct GNUNET_HashCode port;
+ struct GNUNET_HashCode h_port;
/**
* ID of the channel within the tunnel.
/**
- * Message to manage a Channel
- * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY).
+ * Message to acknowledge opening a channel of type
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
+ */
+struct GNUNET_CADET_ChannelOpenAckMessage
+{
+ /**
+ * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * For alignment.
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * ID of the channel
+ */
+ struct GNUNET_CADET_ChannelTunnelNumber ctn;
+
+ /**
+ * Port number of the channel, used to prove to the
+ * initiator that the receiver knows the port.
+ */
+ struct GNUNET_HashCode port;
+};
+
+
+/**
+ * Message to destroy a channel of type
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY.
*/
-struct GNUNET_CADET_ChannelManageMessage
+struct GNUNET_CADET_ChannelDestroyMessage
{
/**
- * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK or
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY
+ * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY
*/
struct GNUNET_MessageHeader header;
* Handle to communicate with the client
*/
struct GNUNET_MQ_Handle *mq;
-
+
/**
* Client handle.
*/
/**
* Ports that this client has declared interest in.
- * Indexed by port, contains *Client.
+ * Indexed by port, contains `struct OpenPort`
*/
struct GNUNET_CONTAINER_MultiHashMap *ports;
unsigned int id;
};
+
/******************************************************************************/
/*********************** GLOBAL VARIABLES ****************************/
/******************************************************************************/
static unsigned int next_client_id;
/**
- * All ports clients of this peer have opened.
+ * All ports clients of this peer have opened. Maps from
+ * a hashed port to a `struct OpenPort`.
*/
struct GNUNET_CONTAINER_MultiHashMap *open_ports;
/**
* Map from ports to channels where the ports were closed at the
* time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
+ * Indexed by h_port, contains `struct CadetChannel`.
*/
struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
/**
- * We had a remote connection @a value to port @a port before
+ * We had a remote connection @a value to port @a h_port before
* client @a cls opened port @a port. Bind them now.
*
* @param cls the `struct CadetClient`
- * @param port the port
+ * @param h_port the hashed port
* @param value the `struct CadetChannel`
* @return #GNUNET_YES (iterate over all such channels)
*/
const struct GNUNET_HashCode *port,
void *value)
{
- struct CadetClient *c = cls;
+ struct OpenPort *op = cls;
struct CadetChannel *ch = value;
GCCH_bind (ch,
- c);
+ op->c,
+ &op->port);
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (loose_channels,
- port,
- value));
+ &op->h_port,
+ ch));
return GNUNET_YES;
}
const struct GNUNET_CADET_PortMessage *pmsg)
{
struct CadetClient *c = cls;
+ struct OpenPort *op;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Open port %s requested by %s\n",
GSC_2s (c));
if (NULL == c->ports)
c->ports = GNUNET_CONTAINER_multihashmap_create (4,
- GNUNET_NO);
+ GNUNET_NO);
+ op = GNUNET_new (struct OpenPort);
+ op->c = c;
+ op->port = pmsg->port;
+ GCCH_hash_port (&op->h_port,
+ &pmsg->port,
+ &my_full_id);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (c->ports,
- &pmsg->port,
- c,
+ &op->port,
+ op,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
{
GNUNET_break (0);
return;
}
(void) GNUNET_CONTAINER_multihashmap_put (open_ports,
- &pmsg->port,
- c,
+ &op->h_port,
+ op,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
- &pmsg->port,
+ &op->h_port,
&bind_loose_channel,
- c);
+ op);
GNUNET_SERVICE_client_continue (c->client);
}
const struct GNUNET_CADET_PortMessage *pmsg)
{
struct CadetClient *c = cls;
+ struct OpenPort *op;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Closing port %s as requested by %s\n",
GNUNET_h2s (&pmsg->port),
GSC_2s (c));
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_remove (c->ports,
- &pmsg->port,
- c))
+ op = GNUNET_CONTAINER_multihashmap_get (c->ports,
+ &pmsg->port);
+ if (NULL == op)
{
GNUNET_break (0);
GNUNET_SERVICE_client_drop (c->client);
return;
}
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->ports,
+ &op->port,
+ op));
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (open_ports,
- &pmsg->port,
- c));
+ &op->h_port,
+ op));
+ GNUNET_free (op);
GNUNET_SERVICE_client_continue (c->client);
}
* A client that created a loose channel that was not bound to a port
* disconnected, drop it from the #loose_channels list.
*
- * @param port the port the channel was trying to bind to
+ * @param h_port the hashed port the channel was trying to bind to
* @param ch the channel that was lost
*/
void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+GSC_drop_loose_channel (const struct GNUNET_HashCode *h_port,
struct CadetChannel *ch)
{
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (loose_channels,
- port,
+ h_port,
ch));
}
/**
* Remove client's ports from the global hashmap on disconnect.
*
- * @param cls Closure (unused).
- * @param key the port.
- * @param value the `struct CadetClient` to remove
+ * @param cls the `struct CadetClient`
+ * @param port the port.
+ * @param value the `struct OpenPort` to remove
* @return #GNUNET_OK, keep iterating.
*/
static int
client_release_ports (void *cls,
- const struct GNUNET_HashCode *key,
+ const struct GNUNET_HashCode *port,
void *value)
{
- struct CadetClient *c = value;
+ struct CadetClient *c = cls;
+ struct OpenPort *op = value;
+ GNUNET_assert (c == op->c);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Closing port %s due to %s disconnect.\n",
- GNUNET_h2s (key),
+ GNUNET_h2s (port),
GSC_2s (c));
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (open_ports,
- key,
- value));
+ &op->h_port,
+ op));
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (c->ports,
- key,
- value));
+ port,
+ op));
+ GNUNET_free (op);
return GNUNET_OK;
}
#define GNUNET_SERVICE_CADET_H
#include "gnunet_util_lib.h"
-#define NEW_CADET 1
#include "cadet_protocol.h"
/**
};
+/**
+ * Port opened by a client.
+ */
+struct OpenPort
+{
+
+ /**
+ * Client that opened the port.
+ */
+ struct CadetClient *c;
+
+ /**
+ * Port number.
+ */
+ struct GNUNET_HashCode port;
+
+ /**
+ * Port hashed with our PID (matches incoming OPEN messages).
+ */
+ struct GNUNET_HashCode h_port;
+
+};
+
+
/**
* Active path through the network (used by a tunnel). There may
* be at most one connection per path.
extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
/**
- * All ports clients of this peer have opened.
+ * All ports clients of this peer have opened. Maps from
+ * a hashed port to a `struct OpenPort`.
*/
extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
/**
* Map from ports to channels where the ports were closed at the
* time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
+ * Indexed by h_port, contains `struct CadetChannel`.
*/
extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
* A client that created a loose channel that was not bound to a port
* disconnected, drop it from the #loose_channels list.
*
- * @param port the port the channel was trying to bind to
+ * @param h_port the hashed port the channel was trying to bind to
* @param ch the channel that was lost
*/
void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+GSC_drop_loose_channel (const struct GNUNET_HashCode *h_port,
struct CadetChannel *ch);
*/
struct GNUNET_HashCode port;
+ /**
+ * Hash'ed port of the channel with initiator and destination PID.
+ */
+ struct GNUNET_HashCode h_port;
+
/**
* Counter for exponential backoff.
*/
}
+/**
+ * Hash the @a port and @a initiator and @a listener to
+ * calculate the "challenge" @a h_port we send to the other
+ * peer on #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN.
+ *
+ * @param[out] h_port set to the hash of @a port, @a initiator and @a listener
+ * @param port cadet port, as seen by CADET clients
+ * @param listener peer that is listining on @a port
+ */
+void
+GCCH_hash_port (struct GNUNET_HashCode *h_port,
+ const struct GNUNET_HashCode *port,
+ const struct GNUNET_PeerIdentity *listener)
+{
+ struct GNUNET_HashContext *hc;
+
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ port,
+ sizeof (*port));
+ GNUNET_CRYPTO_hash_context_read (hc,
+ listener,
+ sizeof (*listener));
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ h_port);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Calculated port hash %s\n",
+ GNUNET_h2s (h_port));
+}
+
+
/**
* Get the channel's public ID.
*
msgcc.header.size = htons (sizeof (msgcc));
msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
msgcc.opt = htonl (options);
- msgcc.port = ch->port;
+ msgcc.h_port = ch->h_port;
msgcc.ctn = ch->ctn;
ch->state = CADET_CHANNEL_OPEN_SENT;
if (NULL != ch->last_control_qe)
ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
ch->owner = ccco;
ch->port = *port;
+ GCCH_hash_port (&ch->h_port,
+ port,
+ GCP_get_id (destination));
if (0 == memcmp (&my_full_id,
GCP_get_id (destination),
sizeof (struct GNUNET_PeerIdentity)))
{
- struct CadetClient *c;
+ struct OpenPort *op;
ch->is_loopback = GNUNET_YES;
- c = GNUNET_CONTAINER_multihashmap_get (open_ports,
- port);
- if (NULL == c)
+ op = GNUNET_CONTAINER_multihashmap_get (open_ports,
+ &ch->h_port);
+ if (NULL == op)
{
/* port closed, wait for it to possibly open */
ch->state = CADET_CHANNEL_LOOSE;
(void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
- port,
+ &ch->h_port,
ch,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
LOG (GNUNET_ERROR_TYPE_DEBUG,
else
{
GCCH_bind (ch,
- c);
+ op->c,
+ &op->port);
}
}
else
*
* @param t tunnel to the remote peer
* @param ctn identifier of this channel in the tunnel
- * @param port desired local port
+ * @param h_port desired hash of local port
* @param options options for the channel
* @return handle to the new channel
*/
struct CadetChannel *
GCCH_channel_incoming_new (struct CadetTunnel *t,
struct GNUNET_CADET_ChannelTunnelNumber ctn,
- const struct GNUNET_HashCode *port,
+ const struct GNUNET_HashCode *h_port,
uint32_t options)
{
struct CadetChannel *ch;
- struct CadetClient *c;
+ struct OpenPort *op;
ch = GNUNET_new (struct CadetChannel);
- ch->port = *port;
+ ch->h_port = *h_port;
ch->t = t;
ch->ctn = ctn;
ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
1,
GNUNET_NO);
- c = GNUNET_CONTAINER_multihashmap_get (open_ports,
- port);
- if (NULL == c)
+ op = GNUNET_CONTAINER_multihashmap_get (open_ports,
+ h_port);
+ if (NULL == op)
{
/* port closed, wait for it to possibly open */
ch->state = CADET_CHANNEL_LOOSE;
(void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
- port,
+ &ch->h_port,
ch,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
GNUNET_assert (NULL == ch->retry_control_task);
else
{
GCCH_bind (ch,
- c);
+ op->c,
+ &op->port);
}
GNUNET_STATISTICS_update (stats,
"# channels",
send_open_ack (void *cls)
{
struct CadetChannel *ch = cls;
- struct GNUNET_CADET_ChannelManageMessage msg;
+ struct GNUNET_CADET_ChannelOpenAckMessage msg;
ch->retry_control_task = NULL;
LOG (GNUNET_ERROR_TYPE_DEBUG,
msg.header.size = htons (sizeof (msg));
msg.reserved = htonl (0);
msg.ctn = ch->ctn;
+ msg.port = ch->port;
if (NULL != ch->last_control_qe)
GCT_send_cancel (ch->last_control_qe);
ch->last_control_qe = GCT_send (ch->t,
* request and establish the link with the client.
*
* @param ch open incoming channel
- * @param c client listening on the respective port
+ * @param c client listening on the respective @a port
+ * @param port the port @a is listening on
*/
void
GCCH_bind (struct CadetChannel *ch,
- struct CadetClient *c)
+ struct CadetClient *c,
+ const struct GNUNET_HashCode *port)
{
uint32_t options;
struct CadetChannelClient *cccd;
cccd = GNUNET_new (struct CadetChannelClient);
GNUNET_assert (NULL == ch->dest);
ch->dest = cccd;
+ ch->port = *port;
cccd->c = c;
cccd->client_ready = GNUNET_YES;
cccd->ccn = GSC_bind (c,
? GCP_get (&my_full_id,
GNUNET_YES)
: GCT_get_destination (ch->t),
- &ch->port,
+ port,
options);
GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
{
ch->state = CADET_CHANNEL_OPEN_SENT;
GCCH_handle_channel_open_ack (ch,
- NULL);
+ NULL,
+ port);
}
else
{
target, but that never went anywhere. Nothing to do here. */
break;
case CADET_CHANNEL_LOOSE:
- GSC_drop_loose_channel (&ch->port,
+ GSC_drop_loose_channel (&ch->h_port,
ch);
break;
default:
/**
* We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
+ * (the port is open on the other side). Verify that the
+ * other end really has the right port, and begin transmissions.
*
* @param ch channel to destroy
* @param cti identifier of the connection that delivered the message
+ * @param port port number (needed to verify receiver knows the port)
*/
void
GCCH_handle_channel_open_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ const struct GNUNET_HashCode *port)
{
switch (ch->state)
{
GNUNET_break_op (0);
return;
}
+ if (0 != memcmp (&ch->port,
+ port,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ /* Other peer failed to provide the right port,
+ refuse connection. */
+ GNUNET_break_op (0);
+ return;
+ }
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
GCCH_2s (ch));
-
/*
This file is part of GNUnet.
Copyright (C) 2001-2017 GNUnet e.V.
struct CadetChannel;
+/**
+ * Hash the @a port and @a initiator and @a listener to
+ * calculate the "challenge" @a h_port we send to the other
+ * peer on #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN.
+ *
+ * @param[out] h_port set to the hash of @a port, @a initiator and @a listener
+ * @param port cadet port, as seen by CADET clients
+ * @param listener peer that is listining on @a port
+ */
+void
+GCCH_hash_port (struct GNUNET_HashCode *h_port,
+ const struct GNUNET_HashCode *port,
+ const struct GNUNET_PeerIdentity *listener);
+
+
/**
* Get the static string for identification of the channel.
*
* request and establish the link with the client.
*
* @param ch open incoming channel
- * @param c client listening on the respective port
+ * @param c client listening on the respective @a port
+ * @param port port number @a c is listening on
*/
void
GCCH_bind (struct CadetChannel *ch,
- struct CadetClient *c);
+ struct CadetClient *c,
+ const struct GNUNET_HashCode *port);
/**
* @param t tunnel to the remote peer
* @param chid identifier of this channel in the tunnel
* @param origin peer to who initiated the channel
- * @param port desired local port
+ * @param h_port hash of desired local port
* @param options options for the channel
* @return handle to the new channel
*/
struct CadetChannel *
GCCH_channel_incoming_new (struct CadetTunnel *t,
struct GNUNET_CADET_ChannelTunnelNumber chid,
- const struct GNUNET_HashCode *port,
+ const struct GNUNET_HashCode *h_port,
uint32_t options);
* @param ch channel to destroy
* @param cti identifier of the connection that delivered the message,
* NULL if the ACK was inferred because we got payload or are on loopback
+ * @param port port number (needed to verify receiver knows the port)
*/
void
GCCH_handle_channel_open_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ const struct GNUNET_HashCode *port);
/**
-
/*
This file is part of GNUnet.
Copyright (C) 2001-2017 GNUnet e.V.
*/
/**
- * @file cadet/gnunet-service-cadet-new_peer.h
+ * @file cadet/gnunet-service-cadet_peer.h
* @brief Information we track per peer.
* @author Bartlomiej Polot
* @author Christian Grothoff
if (NULL != ch)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received duplicate channel CHANNEL_OPEN on port %s from %s (%s), resending ACK\n",
- GNUNET_h2s (&copen->port),
+ "Received duplicate channel CHANNEL_OPEN on h_port %s from %s (%s), resending ACK\n",
+ GNUNET_h2s (&copen->h_port),
GCT_2s (t),
GCCH_2s (ch));
GCCH_handle_duplicate_open (ch,
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received CHANNEL_OPEN on port %s from %s\n",
- GNUNET_h2s (&copen->port),
+ "Received CHANNEL_OPEN on h_port %s from %s\n",
+ GNUNET_h2s (&copen->h_port),
GCT_2s (t));
ch = GCCH_channel_incoming_new (t,
copen->ctn,
- &copen->port,
+ &copen->h_port,
ntohl (copen->opt));
if (NULL != t->destroy_task)
{
GCT_send_channel_destroy (struct CadetTunnel *t,
struct GNUNET_CADET_ChannelTunnelNumber ctn)
{
- struct GNUNET_CADET_ChannelManageMessage msg;
+ struct GNUNET_CADET_ChannelDestroyMessage msg;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Sending DESTORY message for channel ID %u\n",
*/
static void
handle_plaintext_channel_open_ack (void *cls,
- const struct GNUNET_CADET_ChannelManageMessage *cm)
+ const struct GNUNET_CADET_ChannelOpenAckMessage *cm)
{
struct CadetTunnel *t = cls;
struct CadetChannel *ch;
GCCH_2s (ch),
GCT_2s (t));
GCCH_handle_channel_open_ack (ch,
- GCC_get_id (t->current_ct->cc));
+ GCC_get_id (t->current_ct->cc),
+ &cm->port);
}
*/
static void
handle_plaintext_channel_destroy (void *cls,
- const struct GNUNET_CADET_ChannelManageMessage *cm)
+ const struct GNUNET_CADET_ChannelDestroyMessage *cm)
{
struct CadetTunnel *t = cls;
struct CadetChannel *ch;
t),
GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
- struct GNUNET_CADET_ChannelManageMessage,
+ struct GNUNET_CADET_ChannelOpenAckMessage,
t),
GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
- struct GNUNET_CADET_ChannelManageMessage,
+ struct GNUNET_CADET_ChannelDestroyMessage,
t),
GNUNET_MQ_handler_end ()
};