* @author Christian Grothoff
*
* TODO:
- * - implement main BOXed sending logic
- * - figure out what to do with MTU: 1280 for IPv6 is obvious;
- * what for IPv4? 1500? Also, consider differences in
- * headers for with/without box: need to give MIN of both
- * to TNG (as TNG expects a fixed MTU!), or maybe
- * we create a FRESH MQ while we have available BOXes SQNs?
- * (otherwise padding will REALLY hurt)
- * - add and use util/ check for IPv6 availability (#V6)
* - consider imposing transmission limits in the absence
* of ACKs; or: maybe this should be done at TNG service level?
- * - handle addresses discovered fro broadcasts (#)
+ * (at least the receiver might want to enforce limits on
+ * KX/DH operations per sender in here) (#5552)
+ * - overall, we should look more into flow control support
+ * (either in backchannel, or general solution in TNG service)
+ * - handle addresses discovered from broadcasts (#5551)
* (think: what was the story again on address validation?
* where is the API for that!?!)
* - support DNS names in BINDTO option (#5528)
*/
struct SharedSecret *ss_tail;
+ /**
+ * Address of the receiver in the human-readable format
+ * with the #COMMUNICATOR_ADDRESS_PREFIX.
+ */
+ char *foreign_addr;
+
/**
* Address of the other peer.
*/
* Length of the DLL at @a ss_head.
*/
unsigned int num_secrets;
+
+ /**
+ * Number of BOX keys from ACKs we have currently
+ * available for this receiver.
+ */
+ unsigned int acks_available;
/**
* Which network type does this queue use?
receiver->mq = NULL;
GNUNET_MQ_destroy (mq);
}
+ if (NULL != receiver->qh)
+ {
+ GNUNET_TRANSPORT_communicator_mq_del (receiver->qh);
+ receiver->qh = NULL;
+ }
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multipeermap_remove (receivers,
&receiver->target,
GNUNET_CONTAINER_multipeermap_size (receivers),
GNUNET_NO);
GNUNET_free (receiver->address);
+ GNUNET_free (receiver->foreign_addr);
GNUNET_free (receiver);
}
receiver->ss_tail,
ss);
receiver->num_secrets--;
+ receiver->acks_available
+ -= (ss->sequence_allowed - ss->sequence_used);
}
while (NULL != (kce = ss->kce_head))
kce_destroy (kce);
}
+/**
+ * Setup the MQ for the @a receiver. If a queue exists,
+ * the existing one is destroyed. Then the MTU is
+ * recalculated and a fresh queue is initialized.
+ *
+ * @param receiver receiver to setup MQ for
+ */
+static void
+setup_receiver_mq (struct ReceiverAddress *receiver);
+
+
/**
* We received an ACK for @a pid. Check if it is for
* the receiver in @a value and if so, handle it and
&ss->cmac,
sizeof (struct GNUNET_HashCode)))
{
- ss->sequence_allowed = GNUNET_MAX (ss->sequence_allowed,
- ntohl (ack->sequence_max));
- /* move ss to head to avoid discarding it anytime soon! */
- GNUNET_CONTAINER_DLL_remove (receiver->ss_head,
- receiver->ss_tail,
- ss);
- GNUNET_CONTAINER_DLL_insert (receiver->ss_head,
- receiver->ss_tail,
- ss);
- /* FIXME: if this changed sequence_allowed,
- update MTU / MQ of 'receiver'! */
+ uint32_t allowed;
+
+ allowed = ntohl (ack->sequence_max);
+
+ if (allowed > ss->sequence_allowed)
+ {
+ receiver->acks_available += (allowed - ss->sequence_allowed);
+ if ((allowed - ss->sequence_allowed)
+ == receiver->acks_available)
+ {
+ /* we just incremented from zero => MTU change! */
+ setup_receiver_mq (receiver);
+ }
+ ss->sequence_allowed = allowed;
+ /* move ss to head to avoid discarding it anytime soon! */
+ GNUNET_CONTAINER_DLL_remove (receiver->ss_head,
+ receiver->ss_tail,
+ ss);
+ GNUNET_CONTAINER_DLL_insert (receiver->ss_head,
+ receiver->ss_tail,
+ ss);
+ }
return GNUNET_NO;
}
}
"# broadcasts received",
1,
GNUNET_NO);
- // FIXME: we effectively just got a HELLO!
+ // FIXME #5551: we effectively just got a HELLO!
// trigger verification NOW!
return;
}
bindto);
return NULL;
}
- /* FIXME #V6: add test to util/ for IPv6 availability,
- and depending on the result, go directly for v4-only */
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg,
- COMMUNICATOR_CONFIG_SECTION,
- "DISABLE_V6"))
+ if ( (GNUNET_NO ==
+ GNUNET_NETWORK_test_pf (PF_INET6)) ||
+ (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ COMMUNICATOR_CONFIG_SECTION,
+ "DISABLE_V6")) )
{
struct sockaddr_in *i4;
}
+/**
+ * Pad @a dgram by @a pad_size using @a out_cipher.
+ *
+ * @param out_cipher cipher to use
+ * @param dgram datagram to pad
+ * @param pad_size number of bytes of padding to append
+ */
+static void
+do_pad (gcry_cipher_hd_t out_cipher,
+ char *dgram,
+ size_t pad_size)
+{
+ char pad[pad_size];
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ pad,
+ sizeof (pad));
+ if (sizeof (pad) > sizeof (struct GNUNET_MessageHeader))
+ {
+ struct GNUNET_MessageHeader hdr = {
+ .size = htons (sizeof (pad)),
+ .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD)
+ };
+
+ memcpy (pad,
+ &hdr,
+ sizeof (hdr));
+ }
+ GNUNET_assert (0 ==
+ gcry_cipher_encrypt (out_cipher,
+ dgram,
+ sizeof (pad),
+ pad,
+ sizeof (pad)));
+}
+
+
/**
* Signature of functions implementing the sending functionality of a
* message queue.
}
reschedule_receiver_timeout (receiver);
- // FIXME: add support for BOX encryption method!
-
- /* KX encryption method */
+ if (0 == receiver->acks_available)
{
+ /* use KX encryption method */
struct UdpHandshakeSignature uhs;
struct UDPConfirmation uc;
struct InitialKX kx;
msg,
msize));
dpos += msize;
- /* Pad to MTU */
- {
- char pad[sizeof (dgram) - dpos];
-
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- pad,
- sizeof (pad));
- if (sizeof (pad) > sizeof (struct GNUNET_MessageHeader))
- {
- struct GNUNET_MessageHeader hdr = {
- .size = htons (sizeof (pad)),
- .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD)
- };
-
- memcpy (pad,
- &hdr,
- sizeof (hdr));
- GNUNET_assert (0 ==
- gcry_cipher_encrypt (out_cipher,
- &dgram[dpos],
- sizeof (pad),
- pad,
- sizeof (pad)));
- }
- }
+ do_pad (out_cipher,
+ &dgram[dpos],
+ sizeof (dgram) - dpos);
/* Datagram starts with kx */
kx.ephemeral = uhs.ephemeral;
GNUNET_assert (0 ==
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"send");
GNUNET_MQ_impl_send_continue (mq);
+ return;
} /* End of KX encryption method */
+
+ /* begin "BOX" encryption method, scan for ACKs from tail! */
+ for (struct SharedSecret *ss = receiver->ss_tail;
+ NULL != ss;
+ ss = ss->prev)
+ {
+ if (ss->sequence_used < ss->sequence_allowed)
+ {
+ char dgram[sizeof (struct UDPBox) + receiver->mtu];
+ struct UDPBox *box;
+ gcry_cipher_hd_t out_cipher;
+ size_t dpos;
+
+ box = (struct UDPBox *) dgram;
+ ss->sequence_used++;
+ get_kid (&ss->master,
+ ss->sequence_used,
+ &box->kid);
+ setup_cipher (&ss->master,
+ ss->sequence_used,
+ &out_cipher);
+ /* Append encrypted payload to dgram */
+ dpos = sizeof (struct UDPBox);
+ GNUNET_assert (0 ==
+ gcry_cipher_encrypt (out_cipher,
+ &dgram[dpos],
+ msize,
+ msg,
+ msize));
+ dpos += msize;
+ do_pad (out_cipher,
+ &dgram[dpos],
+ sizeof (dgram) - dpos);
+ GNUNET_assert (0 ==
+ gcry_cipher_gettag (out_cipher,
+ box->gcm_tag,
+ sizeof (box->gcm_tag)));
+ gcry_cipher_close (out_cipher);
+ if (-1 ==
+ GNUNET_NETWORK_socket_sendto (udp_sock,
+ dgram,
+ sizeof (dgram),
+ receiver->address,
+ receiver->address_len))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "send");
+ GNUNET_MQ_impl_send_continue (mq);
+ receiver->acks_available--;
+ if (0 == receiver->acks_available)
+ {
+ /* We have no more ACKs => MTU change! */
+ setup_receiver_mq (receiver);
+ }
+ return;
+ }
+ }
+ GNUNET_assert (0);
}
}
+/**
+ * Setup the MQ for the @a receiver. If a queue exists,
+ * the existing one is destroyed. Then the MTU is
+ * recalculated and a fresh queue is initialized.
+ *
+ * @param receiver receiver to setup MQ for
+ */
+static void
+setup_receiver_mq (struct ReceiverAddress *receiver)
+{
+ size_t base_mtu;
+
+ if (NULL != receiver->qh)
+ {
+ GNUNET_TRANSPORT_communicator_mq_del (receiver->qh);
+ receiver->qh = NULL;
+ }
+ GNUNET_assert (NULL == receiver->mq);
+ switch (receiver->address->sa_family)
+ {
+ case AF_INET:
+ base_mtu
+ = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
+ - sizeof (struct GNUNET_TUN_IPv4Header) /* 20 */
+ - sizeof (struct GNUNET_TUN_UdpHeader) /* 8 */;
+ break;
+ case AF_INET6:
+ base_mtu
+ = 1280 /* Minimum MTU required by IPv6 */
+ - sizeof (struct GNUNET_TUN_IPv6Header) /* 40 */
+ - sizeof (struct GNUNET_TUN_UdpHeader) /* 8 */;
+ break;
+ default:
+ GNUNET_assert (0);
+ break;
+ }
+ if (0 == receiver->acks_available)
+ {
+ /* MTU based on full KX messages */
+ receiver->mtu
+ = base_mtu
+ - sizeof (struct InitialKX) /* 48 */
+ - sizeof (struct UDPConfirmation); /* 104 */
+ }
+ else
+ {
+ /* MTU based on BOXed messages */
+ receiver->mtu
+ = base_mtu - sizeof (struct UDPBox);
+ }
+ /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
+ 1404 (IPv4 + Box) bytes, depending on circumstances... */
+ receiver->mq
+ = GNUNET_MQ_queue_for_callbacks (&mq_send,
+ &mq_destroy,
+ &mq_cancel,
+ receiver,
+ NULL,
+ &mq_error,
+ receiver);
+ receiver->qh
+ = GNUNET_TRANSPORT_communicator_mq_add (ch,
+ &receiver->target,
+ receiver->foreign_addr,
+ receiver->mtu,
+ receiver->nt,
+ GNUNET_TRANSPORT_CS_OUTBOUND,
+ receiver->mq);
+}
+
+
/**
* Setup a receiver for transmission. Setup the MQ processing and
* inform transport that the queue is ready.
receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap,
receiver,
receiver->timeout.abs_value_us);
- receiver->mq
- = GNUNET_MQ_queue_for_callbacks (&mq_send,
- &mq_destroy,
- &mq_cancel,
- receiver,
- NULL,
- &mq_error,
- receiver);
- receiver->mtu = 1200 /* FIXME: MTU OK? */;
- if (NULL == timeout_task)
- timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts,
- NULL);
GNUNET_STATISTICS_set (stats,
"# receivers active",
GNUNET_CONTAINER_multipeermap_size (receivers),
GNUNET_NO);
+ switch (address->sa_family)
{
- char *foreign_addr;
-
- switch (address->sa_family)
- {
- case AF_INET:
- GNUNET_asprintf (&foreign_addr,
- "%s-%s",
- COMMUNICATOR_ADDRESS_PREFIX,
- GNUNET_a2s (receiver->address,
- receiver->address_len));
- break;
- case AF_INET6:
- GNUNET_asprintf (&foreign_addr,
- "%s-%s",
- COMMUNICATOR_ADDRESS_PREFIX,
- GNUNET_a2s (receiver->address,
- receiver->address_len));
- break;
- default:
- GNUNET_assert (0);
- }
- receiver->qh
- = GNUNET_TRANSPORT_communicator_mq_add (ch,
- &receiver->target,
- foreign_addr,
- receiver->mtu,
- receiver->nt,
- GNUNET_TRANSPORT_CS_OUTBOUND,
- receiver->mq);
- GNUNET_free (foreign_addr);
+ case AF_INET:
+ GNUNET_asprintf (&receiver->foreign_addr,
+ "%s-%s",
+ COMMUNICATOR_ADDRESS_PREFIX,
+ GNUNET_a2s (receiver->address,
+ receiver->address_len));
+ break;
+ case AF_INET6:
+ GNUNET_asprintf (&receiver->foreign_addr,
+ "%s-%s",
+ COMMUNICATOR_ADDRESS_PREFIX,
+ GNUNET_a2s (receiver->address,
+ receiver->address_len));
+ break;
+ default:
+ GNUNET_assert (0);
}
+
+ setup_receiver_mq (receiver);
+
+ if (NULL == timeout_task)
+ timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts,
+ NULL);
return receiver;
}