remove xt/xu plugins, no longer needed for anything
[oweals/gnunet.git] / src / transport / gnunet-communicator-udp.c
index bbfe2ebec38bdeb5a8f5c37b5044e0c8032cb693..fa8eb6acb913e602e45cf58158795abfccc29ff6 100644 (file)
  * @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)
@@ -535,6 +531,12 @@ struct ReceiverAddress
    */
   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.
    */
@@ -574,6 +576,12 @@ struct ReceiverAddress
    * 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?
@@ -789,6 +797,11 @@ receiver_destroy (struct ReceiverAddress *receiver)
     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,
@@ -800,6 +813,7 @@ receiver_destroy (struct ReceiverAddress *receiver)
                         GNUNET_CONTAINER_multipeermap_size (receivers),
                         GNUNET_NO);
   GNUNET_free (receiver->address);
+  GNUNET_free (receiver->foreign_addr);
   GNUNET_free (receiver);
 }
 
@@ -913,6 +927,8 @@ secret_destroy (struct SharedSecret *ss)
                                 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);
@@ -1252,6 +1268,17 @@ setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral,
 }
 
 
+/**
+ * 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
@@ -1279,17 +1306,28 @@ handle_ack (void *cls,
                     &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;
     }
   }
@@ -1633,7 +1671,7 @@ sock_read (void *cls)
                                "# broadcasts received",
                                1,
                                GNUNET_NO);
-      // FIXME: we effectively just got a HELLO!
+      // FIXME #5551: we effectively just got a HELLO!
       // trigger verification NOW!
       return;
     }
@@ -1745,12 +1783,12 @@ udp_address_to_sockaddr (const char *bindto,
                  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;
       
@@ -1854,6 +1892,43 @@ udp_address_to_sockaddr (const char *bindto,
 }
 
 
+/**
+ * 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.
@@ -1879,10 +1954,9 @@ mq_send (struct GNUNET_MQ_Handle *mq,
   }
   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;
@@ -1935,31 +2009,9 @@ mq_send (struct GNUNET_MQ_Handle *mq,
                                        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 ==
@@ -1979,7 +2031,65 @@ mq_send (struct GNUNET_MQ_Handle *mq,
       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);
 }
 
 
@@ -2043,6 +2153,77 @@ mq_error (void *cls,
 }
 
 
+/**
+ * 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. 
@@ -2073,54 +2254,35 @@ receiver_setup (const struct GNUNET_PeerIdentity *target,
   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;
 }