gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] branch master updated: implemented new DHT path signing with or


From: gnunet
Subject: [gnunet] branch master updated: implemented new DHT path signing with origin authentication
Date: Thu, 07 Jul 2022 20:29:32 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new 3abeb4555 implemented new DHT path signing with origin authentication
3abeb4555 is described below

commit 3abeb45550e1cbf4939583c9b6ff48335fe6f1a9
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Jul 7 20:29:24 2022 +0200

    implemented new DHT path signing with origin authentication
---
 src/cadet/gnunet-service-cadet_dht.c      |   3 +
 src/datacache/plugin_datacache_heap.c     |   5 +-
 src/datacache/plugin_datacache_postgres.c |  30 +-
 src/datacache/plugin_datacache_sqlite.c   |  17 +-
 src/datacache/test_datacache.c            |   6 +
 src/datacache/test_datacache_quota.c      |   3 +
 src/dht/Makefile.am                       |   2 +-
 src/dht/dht.h                             |  27 +-
 src/dht/dht_api.c                         | 308 +++++++++-------
 src/dht/gnunet-dht-get.c                  |   6 +
 src/dht/gnunet-dht-monitor.c              |   8 +-
 src/dht/gnunet-service-dht.h              |   5 +-
 src/dht/gnunet-service-dht_clients.c      | 137 +++++---
 src/dht/gnunet-service-dht_neighbours.c   | 566 ++++++++++++++++++++++--------
 src/dht/gnunet_dht_profiler.c             |   5 +-
 src/dht/test_dht_api.c                    |   1 +
 src/dht/test_dht_monitor.c                |  14 +-
 src/dht/test_dht_topo.c                   |   3 +
 src/fs/gnunet-service-fs_pr.c             |   2 +
 src/gns/gnunet-service-gns_resolver.c     |  10 +-
 src/include/gnunet_datacache_lib.h        |   6 +
 src/include/gnunet_dht_service.h          |  19 +-
 src/pt/gnunet-daemon-pt.c                 |   2 +
 src/regex/regex_internal_dht.c            |   4 +
 24 files changed, 819 insertions(+), 370 deletions(-)

diff --git a/src/cadet/gnunet-service-cadet_dht.c 
b/src/cadet/gnunet-service-cadet_dht.c
index d44a50f50..3df2687de 100644
--- a/src/cadet/gnunet-service-cadet_dht.c
+++ b/src/cadet/gnunet-service-cadet_dht.c
@@ -101,6 +101,7 @@ static struct GNUNET_TIME_Relative announce_delay;
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer peer preceeding with invalid signature, or NULL
  * @param get_path path of the get request
  * @param get_path_length length of @a get_path
  * @param put_path path of the put request
@@ -112,6 +113,7 @@ static struct GNUNET_TIME_Relative announce_delay;
 static void
 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                     const struct GNUNET_HashCode *key,
+                    const struct GNUNET_PeerIdentity *trunc_peer,
                     const struct GNUNET_DHT_PathElement *get_path,
                     unsigned int get_path_length,
                     const struct GNUNET_DHT_PathElement *put_path,
@@ -122,6 +124,7 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute 
exp,
 {
   const struct GNUNET_HELLO_Message *hello = data;
 
+  (void) trunc_peer;
   GCPP_try_path_from_dht (get_path,
                           get_path_length,
                           put_path,
diff --git a/src/datacache/plugin_datacache_heap.c 
b/src/datacache/plugin_datacache_heap.c
index a2b60c8da..0dd8e47f8 100644
--- a/src/datacache/plugin_datacache_heap.c
+++ b/src/datacache/plugin_datacache_heap.c
@@ -196,10 +196,13 @@ heap_plugin_put (void *cls,
   else
     val->distance = xor_distance;
   if (0 != block->put_path_length)
-    val->block.put_path
+  {
+    val->put_path
       = GNUNET_memdup (block->put_path,
                        block->put_path_length
                        * sizeof (struct GNUNET_DHT_PathElement));
+    val->block.put_path = val->put_path;
+  }
   (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
                                             &val->block.key,
                                             val,
diff --git a/src/datacache/plugin_datacache_postgres.c 
b/src/datacache/plugin_datacache_postgres.c
index d9e25992b..b1f9a1b8e 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -71,11 +71,12 @@ init_connection (struct Plugin *plugin)
       "CREATE TEMPORARY SEQUENCE IF NOT EXISTS gn180dc_oid_seq"),
     GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn180dc ("
                             "  oid OID NOT NULL DEFAULT 
nextval('gn180dc_oid_seq'),"
-                            "  type INTEGER NOT NULL,"
-                            "  ro INTEGER NOT NULL,"
-                            "  prox INTEGER NOT NULL,"
-                            "  expiration_time BIGINT NOT NULL,"
-                            "  key BYTEA NOT NULL,"
+                            "  type INT4 NOT NULL,"
+                            "  ro INT4 NOT NULL,"
+                            "  prox INT4 NOT NULL,"
+                            "  expiration_time INT8 NOT NULL,"
+                            "  key BYTEA NOT NULL CHECK(LENGTH(key)=64),"
+                            "  trunc BYTEA NOT NULL CHECK(LENGTH(trunc)=32),"
                             "  value BYTEA NOT NULL,"
                             "  path BYTEA DEFAULT NULL)"),
     GNUNET_PQ_make_try_execute (
@@ -93,11 +94,11 @@ init_connection (struct Plugin *plugin)
   };
   struct GNUNET_PQ_PreparedStatement ps[] = {
     GNUNET_PQ_make_prepare ("getkt",
-                            "SELECT expiration_time,type,ro,value,path FROM 
gn180dc "
+                            "SELECT expiration_time,type,ro,value,trunc,path 
FROM gn180dc "
                             "WHERE key=$1 AND type=$2 AND expiration_time >= 
$3",
                             3),
     GNUNET_PQ_make_prepare ("getk",
-                            "SELECT expiration_time,type,ro,value,path FROM 
gn180dc "
+                            "SELECT expiration_time,type,ro,value,trunc,path 
FROM gn180dc "
                             "WHERE key=$1 AND expiration_time >= $2",
                             2),
     GNUNET_PQ_make_prepare ("getex",
@@ -110,14 +111,14 @@ init_connection (struct Plugin *plugin)
                             " ORDER BY prox ASC, expiration_time ASC LIMIT 1",
                             0),
     GNUNET_PQ_make_prepare ("get_closest",
-                            "(SELECT expiration_time,type,ro,value,path,key 
FROM gn180dc"
+                            "(SELECT 
expiration_time,type,ro,value,trunc,path,key FROM gn180dc"
                             " WHERE key >= $1"
                             "   AND expiration_time >= $2"
                             "   AND ( (type = $3) OR ( 0 = $3) )"
                             " ORDER BY key ASC"
                             " LIMIT $4)"
                             " UNION "
-                            "(SELECT expiration_time,type,ro,value,path,key 
FROM gn180dc"
+                            "(SELECT 
expiration_time,type,ro,value,trunc,path,key FROM gn180dc"
                             " WHERE key <= $1"
                             "   AND expiration_time >= $2"
                             "   AND ( (type = $3) OR ( 0 = $3) )"
@@ -129,9 +130,9 @@ init_connection (struct Plugin *plugin)
                             1),
     GNUNET_PQ_make_prepare ("put",
                             "INSERT INTO gn180dc"
-                            " (type, ro, prox, expiration_time, key, value, 
path) "
-                            "VALUES ($1, $2, $3, $4, $5, $6, $7)",
-                            7),
+                            " (type, ro, prox, expiration_time, key, value, 
trunc, path) "
+                            "VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
+                            8),
     GNUNET_PQ_PREPARED_STATEMENT_END
   };
 
@@ -170,6 +171,7 @@ postgres_plugin_put (void *cls,
     GNUNET_PQ_query_param_auto_from_type (&block->key),
     GNUNET_PQ_query_param_fixed_size (block->data,
                                       block->data_size),
+    GNUNET_PQ_query_param_auto_from_type (&block->trunc_peer),
     GNUNET_PQ_query_param_fixed_size (block->put_path,
                                       block->put_path_length
                                       * sizeof(struct GNUNET_DHT_PathElement)),
@@ -243,6 +245,8 @@ handle_results (void *cls,
       GNUNET_PQ_result_spec_variable_size ("value",
                                            &data,
                                            &block.data_size),
+      GNUNET_PQ_result_spec_auto_from_type ("trunc",
+                                            &block.trunc_peer),
       GNUNET_PQ_result_spec_variable_size ("path",
                                            &path,
                                            &path_size),
@@ -465,6 +469,8 @@ extract_result_cb (void *cls,
       GNUNET_PQ_result_spec_variable_size ("value",
                                            &data,
                                            &block.data_size),
+      GNUNET_PQ_result_spec_auto_from_type ("trunc",
+                                            &block.trunc_peer),
       GNUNET_PQ_result_spec_variable_size ("path",
                                            &path,
                                            &path_size),
diff --git a/src/datacache/plugin_datacache_sqlite.c 
b/src/datacache/plugin_datacache_sqlite.c
index 22ae5c0f5..0753d87ce 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -207,6 +207,7 @@ sqlite_plugin_put (void *cls,
     GNUNET_SQ_query_param_fixed_size (block->put_path,
                                       block->put_path_length
                                       * sizeof(struct GNUNET_DHT_PathElement)),
+    GNUNET_SQ_query_param_auto_from_type (&block->trunc_peer),
     GNUNET_SQ_query_param_end
   };
 
@@ -290,6 +291,7 @@ get_any (void *cls,
     GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
     GNUNET_SQ_result_spec_variable_size (&path,
                                          &path_size),
+    GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
     GNUNET_SQ_result_spec_uint32 (&btype32),
     GNUNET_SQ_result_spec_uint32 (&bro32),
     GNUNET_SQ_result_spec_end
@@ -451,6 +453,7 @@ get_typed (void *cls,
     GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
     GNUNET_SQ_result_spec_variable_size (&path,
                                          &path_size),
+    GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
     GNUNET_SQ_result_spec_uint32 (&bro32),
     GNUNET_SQ_result_spec_end
   };
@@ -749,6 +752,7 @@ sqlite_plugin_get_closest (void *cls,
     GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
     GNUNET_SQ_result_spec_variable_size (&path,
                                          &path_size),
+    GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
     GNUNET_SQ_result_spec_uint32 (&rtype32),
     GNUNET_SQ_result_spec_uint32 (&bro32),
     GNUNET_SQ_result_spec_auto_from_type (&block.key),
@@ -882,6 +886,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                 "  key BLOB NOT NULL DEFAULT '',"
                 "  prox INTEGER NOT NULL,"
                 "  value BLOB NOT NULL,"
+                "  trunc BLOB NOT NULL,"
                 "  path BLOB DEFAULT '')");
   SQLITE3_EXEC (dbh,
                 "CREATE INDEX idx_hashidx"
@@ -900,8 +905,8 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
   if ((SQLITE_OK !=
        sq_prepare (plugin->dbh,
                    "INSERT INTO ds180"
-                   " (type, ro, expire, key, prox, value, path)"
-                   " VALUES (?, ?, ?, ?, ?, ?, ?)",
+                   " (type, ro, expire, key, prox, value, path, trunc)"
+                   " VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
                    &plugin->insert_stmt)) ||
       (SQLITE_OK !=
        sq_prepare (plugin->dbh,
@@ -917,7 +922,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                    &plugin->get_count_any_stmt)) ||
       (SQLITE_OK !=
        sq_prepare (plugin->dbh,
-                   "SELECT value,expire,path,ro"
+                   "SELECT value,expire,path,trunc,ro"
                    " FROM ds180"
                    " WHERE key=?"
                    " AND type=?"
@@ -926,7 +931,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                    &plugin->get_stmt)) ||
       (SQLITE_OK !=
        sq_prepare (plugin->dbh,
-                   "SELECT value,expire,path,type,ro"
+                   "SELECT value,expire,path,trunc,type,ro"
                    " FROM ds180"
                    " WHERE key=?"
                    " AND expire >= ?"
@@ -950,7 +955,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
       (SQLITE_OK !=
        sq_prepare (plugin->dbh,
                    "SELECT * FROM ("
-                   " SELECT value,expire,path,type,ro,key"
+                   " SELECT value,expire,path,trunc,type,ro,key"
                    " FROM ds180 "
                    " WHERE key>=?1 "
                    "  AND expire >= ?2"
@@ -958,7 +963,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                    " ORDER BY KEY ASC LIMIT ?4)"
                    "UNION "
                    "SELECT * FROM ("
-                   " SELECT value,expire,path,type,ro,key"
+                   " SELECT value,expire,path,trunc,type,ro,key"
                    " FROM ds180 "
                    " WHERE key<=?1 "
                    "  AND expire >= ?2"
diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c
index b5d978995..fd5a5f54c 100644
--- a/src/datacache/test_datacache.c
+++ b/src/datacache/test_datacache.c
@@ -97,6 +97,9 @@ run (void *cls,
     block.key = k;
     block.data = &n;
     block.data_size = sizeof (n);
+    memset (&block.trunc_peer,
+            43,
+            sizeof (block.trunc_peer));
     block.ro = 42;
     block.type = (enum GNUNET_BLOCK_Type) (1 + i % 16);
     block.put_path = NULL;
@@ -134,6 +137,9 @@ run (void *cls,
   block.data = &n;
   block.data_size = sizeof (n);
   block.ro = 42;
+  memset (&block.trunc_peer,
+          44,
+          sizeof (block.trunc_peer));
   block.type = (enum GNUNET_BLOCK_Type) 792;
   block.put_path = NULL;
   block.put_path_length = 0;
diff --git a/src/datacache/test_datacache_quota.c 
b/src/datacache/test_datacache_quota.c
index 0b647ee99..994147a64 100644
--- a/src/datacache/test_datacache_quota.c
+++ b/src/datacache/test_datacache_quota.c
@@ -92,6 +92,9 @@ run (void *cls,
       block.key = k;
       block.data = buf;
       block.data_size = j;
+      memset (&block.trunc_peer,
+              43,
+              sizeof (block.trunc_peer));
       block.ro = 42;
       block.type = (enum GNUNET_BLOCK_Type) (1 + i);
       block.put_path = NULL;
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
index 68a17723d..124f95a77 100644
--- a/src/dht/Makefile.am
+++ b/src/dht/Makefile.am
@@ -26,7 +26,7 @@ libgnunetdht_la_LIBADD = \
   $(LTLIBINTL)
 libgnunetdht_la_LDFLAGS = \
   $(GN_LIB_LDFLAGS)  \
-  -version-info 3:0:0
+  -version-info 4:0:0
 
 
 plugin_LTLIBRARIES = \
diff --git a/src/dht/dht.h b/src/dht/dht.h
index c69b69f07..6a137defe 100644
--- a/src/dht/dht.h
+++ b/src/dht/dht.h
@@ -152,6 +152,16 @@ struct GNUNET_DHT_ClientResultMessage
    */
   uint32_t type GNUNET_PACKED;
 
+  /**
+   * Reserved, always 0.
+   */
+  uint32_t reserved GNUNET_PACKED;
+
+  /**
+   * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
+   */
+  uint32_t options GNUNET_PACKED;
+
   /**
    * Number of peers recorded in the outgoing path from source to the
    * storgage location of this message.
@@ -179,7 +189,7 @@ struct GNUNET_DHT_ClientResultMessage
    */
   struct GNUNET_HashCode key GNUNET_PACKED;
 
-  /* put path, get path and actual data are copied to end of this dealy do */
+  /* trunc_peer, put path, get path and actual data are copied to end of this 
dealy do */
 };
 
 
@@ -348,10 +358,9 @@ struct GNUNET_DHT_MonitorGetMessage
   uint32_t desired_replication_level GNUNET_PACKED;
 
   /**
-   * Number of peers recorded in the outgoing path from source to the
-   * storage location of this message.
+   * Always zero.
    */
-  uint32_t get_path_length GNUNET_PACKED;
+  uint32_t reserved GNUNET_PACKED;
 
   /**
    * The key to store the value under.
@@ -376,6 +385,16 @@ struct GNUNET_DHT_MonitorGetRespMessage
    */
   uint32_t type GNUNET_PACKED;
 
+  /**
+   * Reserved, always 0.
+   */
+  uint32_t reserved GNUNET_PACKED;
+
+  /**
+   * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
+   */
+  uint32_t options GNUNET_PACKED;
+
   /**
    * Length of the PUT path that follows (if tracked).
    */
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
index 474198004..5fa8f759f 100644
--- a/src/dht/dht_api.c
+++ b/src/dht/dht_api.c
@@ -525,31 +525,6 @@ mq_error_handler (void *cls,
 }
 
 
-/**
- * Verify integrity of a get monitor message from the service.
- *
- * @param cls The DHT handle.
- * @param msg Monitor get message from the service.
- * @return #GNUNET_OK if everything went fine,
- *         #GNUNET_SYSERR if the message is malformed.
- */
-static enum GNUNET_GenericReturnValue
-check_monitor_get (void *cls,
-                   const struct GNUNET_DHT_MonitorGetMessage *msg)
-{
-  uint32_t plen = ntohl (msg->get_path_length);
-  uint16_t msize = ntohs (msg->header.size) - sizeof(*msg);
-
-  if ((plen > UINT16_MAX) ||
-      (plen * sizeof(struct GNUNET_DHT_PathElement) != msize))
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Process a get monitor message from the service.
  *
@@ -561,6 +536,8 @@ handle_monitor_get (void *cls,
                     const struct GNUNET_DHT_MonitorGetMessage *msg)
 {
   struct GNUNET_DHT_Handle *handle = cls;
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
 
   for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
        NULL != mh;
@@ -568,20 +545,19 @@ handle_monitor_get (void *cls,
   {
     if (NULL == mh->get_cb)
       continue;
-    if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
-         (mh->type == ntohl (msg->type))) &&
-        ((NULL == mh->key) ||
-         (0 == memcmp (mh->key,
-                       &msg->key,
-                       sizeof(struct GNUNET_HashCode)))))
-      mh->get_cb (mh->cb_cls,
-                  ntohl (msg->options),
-                  (enum GNUNET_BLOCK_Type) ntohl (msg->type),
-                  ntohl (msg->hop_count),
-                  ntohl (msg->desired_replication_level),
-                  ntohl (msg->get_path_length),
-                  (struct GNUNET_DHT_PathElement *) &msg[1],
-                  &msg->key);
+    if ( (GNUNET_BLOCK_TYPE_ANY != mh->type) &&
+         (mh->type != ntohl (msg->type)))
+      continue;
+    if ( (NULL != mh->key) &&
+         (0 != GNUNET_memcmp (mh->key,
+                              &msg->key)) )
+      continue;
+    mh->get_cb (mh->cb_cls,
+                ro,
+                (enum GNUNET_BLOCK_Type) ntohl (msg->type),
+                ntohl (msg->hop_count),
+                ntohl (msg->desired_replication_level),
+                &msg->key);
   }
 }
 
@@ -601,7 +577,19 @@ check_monitor_get_resp (void *cls,
   size_t msize = ntohs (msg->header.size) - sizeof(*msg);
   uint32_t getl = ntohl (msg->get_path_length);
   uint32_t putl = ntohl (msg->put_path_length);
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
 
+  if (truncated)
+  {
+    if (msize < sizeof (struct GNUNET_PeerIdentity))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    msize -= sizeof (struct GNUNET_PeerIdentity);
+  }
   if ((getl + putl < getl) ||
       ((msize / sizeof(struct GNUNET_DHT_PathElement)) < getl + putl))
   {
@@ -624,35 +612,47 @@ handle_monitor_get_resp (void *cls,
 {
   struct GNUNET_DHT_Handle *handle = cls;
   size_t msize = ntohs (msg->header.size) - sizeof(*msg);
-  const struct GNUNET_DHT_PathElement *path;
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
   uint32_t getl = ntohl (msg->get_path_length);
   uint32_t putl = ntohl (msg->put_path_length);
-
-
-  path = (const struct GNUNET_DHT_PathElement *) &msg[1];
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? (const struct GNUNET_PeerIdentity *) &msg[1]
+    : NULL;
+  const struct GNUNET_DHT_PathElement *path
+    = truncated
+    ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
+    : (const struct GNUNET_DHT_PathElement *) &msg[1];
+
+  if (truncated)
+    msize -= sizeof (struct GNUNET_PeerIdentity);
+  msize -= sizeof(struct GNUNET_DHT_PathElement) * (putl + getl);
   for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
        NULL != mh;
        mh = mh->next)
   {
     if (NULL == mh->get_resp_cb)
       continue;
-    if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
-         (mh->type == ntohl (msg->type))) &&
-        ((NULL == mh->key) ||
-         (0 == memcmp (mh->key,
-                       &msg->key,
-                       sizeof(struct GNUNET_HashCode)))))
-      mh->get_resp_cb (mh->cb_cls,
-                       (enum GNUNET_BLOCK_Type) ntohl (msg->type),
-                       &path[putl],
-                       getl,
-                       path,
-                       putl,
-                       GNUNET_TIME_absolute_ntoh (msg->expiration_time),
-                       &msg->key,
-                       (const void *) &path[getl + putl],
-                       msize - sizeof(struct GNUNET_DHT_PathElement) * (putl
-                                                                        + 
getl));
+    if ( (GNUNET_BLOCK_TYPE_ANY != mh->type) &&
+         (mh->type != ntohl (msg->type)) )
+      continue;
+    if ( (NULL != mh->key) &&
+         (0 != GNUNET_memcmp (mh->key,
+                              &msg->key)) )
+      continue;
+    mh->get_resp_cb (mh->cb_cls,
+                     (enum GNUNET_BLOCK_Type) ntohl (msg->type),
+                     trunc_peer,
+                     &path[putl],
+                     getl,
+                     path,
+                     putl,
+                     GNUNET_TIME_absolute_ntoh (msg->expiration_time),
+                     &msg->key,
+                     (const void *) &path[getl + putl],
+                     msize);
   }
 }
 
@@ -669,11 +669,21 @@ static enum GNUNET_GenericReturnValue
 check_monitor_put (void *cls,
                    const struct GNUNET_DHT_MonitorPutMessage *msg)
 {
-  size_t msize;
-  uint32_t putl;
+  size_t msize = ntohs (msg->header.size) - sizeof(*msg);
+  uint32_t putl = ntohl (msg->put_path_length);
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
 
-  msize = ntohs (msg->header.size) - sizeof(*msg);
-  putl = ntohl (msg->put_path_length);
+  if (truncated)
+  {
+    if (msize < sizeof (struct GNUNET_PeerIdentity))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    msize -= sizeof (struct GNUNET_PeerIdentity);
+  }
   if ((msize / sizeof(struct GNUNET_DHT_PathElement)) < putl)
   {
     GNUNET_break (0);
@@ -696,31 +706,46 @@ handle_monitor_put (void *cls,
   struct GNUNET_DHT_Handle *handle = cls;
   size_t msize = ntohs (msg->header.size) - sizeof(*msg);
   uint32_t putl = ntohl (msg->put_path_length);
-  const struct GNUNET_DHT_PathElement *path;
-  struct GNUNET_DHT_MonitorHandle *mh;
-
-  path = (const struct GNUNET_DHT_PathElement *) &msg[1];
-  for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? (const struct GNUNET_PeerIdentity *) &msg[1]
+    : NULL;
+  const struct GNUNET_DHT_PathElement *path
+    = truncated
+    ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
+    : (const struct GNUNET_DHT_PathElement *) &msg[1];
+
+  if (truncated)
+    msize -= sizeof (struct GNUNET_PeerIdentity);
+  msize -= sizeof(struct GNUNET_DHT_PathElement) * putl;
+  for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
+       NULL != mh;
+       mh = mh->next)
   {
     if (NULL == mh->put_cb)
       continue;
-    if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
-         (mh->type == ntohl (msg->type))) &&
-        ((NULL == mh->key) ||
-         (0 == memcmp (mh->key,
-                       &msg->key,
-                       sizeof(struct GNUNET_HashCode)))))
-      mh->put_cb (mh->cb_cls,
-                  ntohl (msg->options),
-                  (enum GNUNET_BLOCK_Type) ntohl (msg->type),
-                  ntohl (msg->hop_count),
-                  ntohl (msg->desired_replication_level),
-                  putl,
-                  path,
-                  GNUNET_TIME_absolute_ntoh (msg->expiration_time),
-                  &msg->key,
-                  (const void *) &path[putl],
-                  msize - sizeof(struct GNUNET_DHT_PathElement) * putl);
+    if ( (GNUNET_BLOCK_TYPE_ANY != mh->type) &&
+         (mh->type != ntohl (msg->type)) )
+      continue;
+    if ( (NULL != mh->key) &&
+         (0 != GNUNET_memcmp (mh->key,
+                              &msg->key)) )
+      continue;
+    mh->put_cb (mh->cb_cls,
+                ro,
+                (enum GNUNET_BLOCK_Type) ntohl (msg->type),
+                ntohl (msg->hop_count),
+                ntohl (msg->desired_replication_level),
+                trunc_peer,
+                putl,
+                path,
+                GNUNET_TIME_absolute_ntoh (msg->expiration_time),
+                &msg->key,
+                (const void *) &path[putl],
+                msize);
   }
 }
 
@@ -740,15 +765,25 @@ check_client_result (void *cls,
   size_t msize = ntohs (msg->header.size) - sizeof(*msg);
   uint32_t put_path_length = ntohl (msg->put_path_length);
   uint32_t get_path_length = ntohl (msg->get_path_length);
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
   size_t meta_length;
 
-  meta_length =
-    sizeof(struct GNUNET_DHT_PathElement) * (get_path_length + 
put_path_length);
-  if ((msize < meta_length) ||
-      (get_path_length >
-       GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
-      (put_path_length >
-       GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)))
+  if (truncated)
+  {
+    if (msize < sizeof (struct GNUNET_PeerIdentity))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    msize -= sizeof (struct GNUNET_PeerIdentity);
+  }
+  meta_length = msize / sizeof(struct GNUNET_DHT_PathElement);
+  if ( (get_path_length + put_path_length >
+        meta_length) ||
+       (get_path_length + put_path_length <
+        get_path_length) )
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -774,21 +809,35 @@ process_client_result (void *cls,
   struct GNUNET_DHT_GetHandle *get_handle = value;
   size_t msize = ntohs (crm->header.size) - sizeof(*crm);
   uint16_t type = ntohl (crm->type);
-  uint32_t put_path_length = ntohl (crm->put_path_length);
-  uint32_t get_path_length = ntohl (crm->get_path_length);
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (crm->options);
+  bool truncated
+    = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  uint32_t put_path_length
+    = ntohl (crm->put_path_length);
+  uint32_t get_path_length
+    = ntohl (crm->get_path_length);
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? (const struct GNUNET_PeerIdentity *) &crm[1]
+    : NULL;
   const struct GNUNET_DHT_PathElement *put_path
-    = (const struct GNUNET_DHT_PathElement *) &crm[1];
+    = truncated
+    ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
+    : (const struct GNUNET_DHT_PathElement *) &crm[1];
   const struct GNUNET_DHT_PathElement *get_path
     = &put_path[put_path_length];
   const void *data
     = &get_path[get_path_length];
   size_t meta_length
-    = sizeof(struct GNUNET_DHT_PathElement) * (get_path_length
-                                               + put_path_length);
+    = sizeof(struct GNUNET_DHT_PathElement)
+      * (get_path_length + put_path_length);
   size_t data_length
     = msize - meta_length;
   struct GNUNET_HashCode hc;
 
+  if (truncated)
+    data_length -= sizeof (struct GNUNET_PeerIdentity);
   if (crm->unique_id != get_handle->unique_id)
   {
     /* UID mismatch */
@@ -837,6 +886,7 @@ process_client_result (void *cls,
   get_handle->iter (get_handle->iter_cls,
                     GNUNET_TIME_absolute_ntoh (crm->expiration),
                     key,
+                    trunc_peer,
                     get_path,
                     get_path_length,
                     put_path,
@@ -945,10 +995,10 @@ static enum GNUNET_GenericReturnValue
 try_connect (struct GNUNET_DHT_Handle *h)
 {
   struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (monitor_get,
-                           GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET,
-                           struct GNUNET_DHT_MonitorGetMessage,
-                           h),
+    GNUNET_MQ_hd_fixed_size (monitor_get,
+                             GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET,
+                             struct GNUNET_DHT_MonitorGetMessage,
+                             h),
     GNUNET_MQ_hd_var_size (monitor_get_resp,
                            GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP,
                            struct GNUNET_DHT_MonitorGetRespMessage,
@@ -1303,19 +1353,19 @@ unsigned int
 GNUNET_DHT_verify_path (const void *data,
                         size_t data_size,
                         struct GNUNET_TIME_Absolute exp_time,
+                        const struct GNUNET_PeerIdentity *bpid,
                         const struct GNUNET_DHT_PathElement *put_path,
                         unsigned int put_path_len,
                         const struct GNUNET_DHT_PathElement *get_path,
                         unsigned int get_path_len,
                         const struct GNUNET_PeerIdentity *me)
 {
+  static struct GNUNET_PeerIdentity zero;
   struct GNUNET_DHT_HopSignature hs = {
     .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
     .purpose.size = htonl (sizeof (hs)),
     .expiration_time = GNUNET_TIME_absolute_hton (exp_time)
   };
-  const struct GNUNET_PeerIdentity *pred;
-  const struct GNUNET_PeerIdentity *succ;
   unsigned int i;
 
   if (0 == get_path_len + put_path_len)
@@ -1336,38 +1386,56 @@ GNUNET_DHT_verify_path (const void *data,
                 j,
                 GNUNET_i2s (&get_path[j].pred));
 
-  i = put_path_len + get_path_len - 1;
   GNUNET_CRYPTO_hash (data,
                       data_size,
                       &hs.h_data);
+  i = put_path_len + get_path_len;
   while (i > 0)
   {
-    pred = (i - 1 >= put_path_len)
-      ? &get_path[i - put_path_len - 1].pred
-      : &put_path[i - 1].pred;
-    if (i + 1 == get_path_len + put_path_len)
+    const struct GNUNET_PeerIdentity *pred;
+    const struct GNUNET_PeerIdentity *succ;
+    const struct GNUNET_DHT_PathElement *pe;
+
+    i--;
+    if (0 == i)
+    {
+      pred = (NULL == bpid) ? &zero : bpid;
+    }
+    else
+    {
+      unsigned int off = i - 1;
+
+      pred = (off >= put_path_len)
+        ? &get_path[off - put_path_len].pred
+        : &put_path[off].pred;
+    }
+    if (i == get_path_len + put_path_len - 1)
+    {
       succ = me;
+    }
     else
-      succ = (i + 1 >= put_path_len)
-        ? &get_path[i + 1 - put_path_len].pred
-        : &put_path[i + 1].pred;
+    {
+      unsigned int off = i + 1;
+
+      succ = (off >= put_path_len)
+        ? &get_path[off - put_path_len].pred
+        : &put_path[off].pred;
+    }
     hs.pred = *pred;
     hs.succ = *succ;
+    pe = (i >= put_path_len)
+      ? &get_path[i - put_path_len]
+      : &put_path[i];
     if (GNUNET_OK !=
         GNUNET_CRYPTO_eddsa_verify (
           GNUNET_SIGNATURE_PURPOSE_DHT_HOP,
           &hs,
-          (i - 1 >= put_path_len)
-            ? &get_path[i - put_path_len - 1].sig
-          : &put_path[i - 1].sig,
-          (i >= put_path_len)
-          ? &get_path[i - put_path_len].pred.public_key
-          : &put_path[i].pred.public_key))
+          &pe->sig,
+          &pe->pred.public_key))
     {
       GNUNET_break_op (0);
-      return i;
+      return i + 1;
     }
-    i--;
   }
   return i;
 }
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c
index 42ffe75ba..806cafd0d 100644
--- a/src/dht/gnunet-dht-get.c
+++ b/src/dht/gnunet-dht-get.c
@@ -139,6 +139,7 @@ timeout_task (void *cls)
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer peer at which the path was truncated, or NULL if not
  * @param get_path peers on reply path (or NULL if not recorded)
  * @param get_path_length number of entries in get_path
  * @param put_path peers on the PUT path (or NULL if not recorded)
@@ -151,6 +152,7 @@ static void
 get_result_iterator (void *cls,
                      struct GNUNET_TIME_Absolute exp,
                      const struct GNUNET_HashCode *key,
+                     const struct GNUNET_PeerIdentity *trunc_peer,
                      const struct GNUNET_DHT_PathElement *get_path,
                      unsigned int get_path_length,
                      const struct GNUNET_DHT_PathElement *put_path,
@@ -183,6 +185,10 @@ get_result_iterator (void *cls,
                "%s%s",
                (0 == i) ? "" : "-",
                GNUNET_i2s (&put_path[i].pred));
+    if (NULL != trunc_peer)
+      fprintf (stdout,
+               "T%s",
+               GNUNET_i2s (trunc_peer));
     fprintf (stdout,
              "\n");
   }
diff --git a/src/dht/gnunet-dht-monitor.c b/src/dht/gnunet-dht-monitor.c
index b4ec497e4..93ea1284a 100644
--- a/src/dht/gnunet-dht-monitor.c
+++ b/src/dht/gnunet-dht-monitor.c
@@ -125,8 +125,6 @@ timeout_task (void *cls)
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
- * @param path_length number of entries in path (or 0 if not recorded).
- * @param path peers on the GET path (or NULL if not recorded).
  * @param desired_replication_level Desired replication level.
  * @param key Key of the requested data.
  */
@@ -136,8 +134,6 @@ get_callback (void *cls,
               enum GNUNET_BLOCK_Type type,
               uint32_t hop_count,
               uint32_t desired_replication_level,
-              unsigned int path_length,
-              const struct GNUNET_DHT_PathElement *path,
               const struct GNUNET_HashCode *key)
 {
   fprintf (stdout,
@@ -154,6 +150,7 @@ get_callback (void *cls,
  *
  * @param cls Closure.
  * @param type The type of data in the result.
+ * @param trunc_peer peer where the path was truncated, or NULL if the path is 
complete
  * @param get_path Peers on GET path (or NULL if not recorded).
  * @param get_path_length number of entries in get_path.
  * @param put_path peers on the PUT path (or NULL if not recorded).
@@ -166,6 +163,7 @@ get_callback (void *cls,
 static void
 get_resp_callback (void *cls,
                    enum GNUNET_BLOCK_Type type,
+                   const struct GNUNET_PeerIdentity *trunc_peer,
                    const struct GNUNET_DHT_PathElement *get_path,
                    unsigned int get_path_length,
                    const struct GNUNET_DHT_PathElement *put_path,
@@ -196,6 +194,7 @@ get_resp_callback (void *cls,
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
+ * @param trunc_peer peer where the path was truncated, or NULL if the path is 
complete
  * @param path_length number of entries in path (or 0 if not recorded).
  * @param path peers on the PUT path (or NULL if not recorded).
  * @param desired_replication_level Desired replication level.
@@ -210,6 +209,7 @@ put_callback (void *cls,
               enum GNUNET_BLOCK_Type type,
               uint32_t hop_count,
               uint32_t desired_replication_level,
+              const struct GNUNET_PeerIdentity *trunc_peer,
               unsigned int path_length,
               const struct GNUNET_DHT_PathElement *path,
               struct GNUNET_TIME_Absolute exp,
diff --git a/src/dht/gnunet-service-dht.h b/src/dht/gnunet-service-dht.h
index 5507dcea0..ecb79fa50 100644
--- a/src/dht/gnunet-service-dht.h
+++ b/src/dht/gnunet-service-dht.h
@@ -144,6 +144,7 @@ GDS_u_hold (struct GDS_Underlay *u,
  *
  * @param bd block details
  * @param query_hash hash of the original query, might not match key in @a bd
+ * @param trunc_peer peer at which the path was truncated, or NULL if path 
starts at the origin
  * @param get_path_length number of entries in @a get_path
  * @param get_path path the reply has taken
  * @return true on success, false on failures
@@ -162,8 +163,6 @@ GDS_CLIENTS_handle_reply (const struct 
GNUNET_DATACACHE_Block *bd,
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
- * @param path_length number of entries in path (or 0 if not recorded).
- * @param path peers on the GET path (or NULL if not recorded).
  * @param desired_replication_level Desired replication level.
  * @param key Key of the requested data.
  */
@@ -172,8 +171,6 @@ GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption 
options,
                          enum GNUNET_BLOCK_Type type,
                          uint32_t hop_count,
                          uint32_t desired_replication_level,
-                         unsigned int path_length,
-                         const struct GNUNET_DHT_PathElement *path,
                          const struct GNUNET_HashCode *key);
 
 
diff --git a/src/dht/gnunet-service-dht_clients.c 
b/src/dht/gnunet-service-dht_clients.c
index 631c4f68b..fdcc31f13 100644
--- a/src/dht/gnunet-service-dht_clients.c
+++ b/src/dht/gnunet-service-dht_clients.c
@@ -656,8 +656,6 @@ handle_dht_local_get (void *cls,
                            cqr->type,
                            0, /* hop count */
                            cqr->replication,
-                           0, /* path length */
-                           NULL,
                            &get->key);
   /* start remote requests */
   if (NULL != retry_task)
@@ -907,12 +905,15 @@ forward_reply (void *cls,
 {
   struct ForwardReplyContext *frc = cls;
   struct ClientQueryRecord *record = value;
+  const struct GNUNET_DATACACHE_Block *bd = frc->bd;
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_DHT_ClientResultMessage *reply;
   enum GNUNET_BLOCK_ReplyEvaluationResult eval;
   bool do_free;
   struct GNUNET_HashCode ch;
   struct GNUNET_DHT_PathElement *paths;
+  bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
+  size_t xsize = bd->data_size;
 
   LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
                "CLIENT-RESULT %s\n",
@@ -995,18 +996,34 @@ forward_reply (void *cls,
                             "# RESULTS queued for clients",
                             1,
                             GNUNET_NO);
+  xsize += (frc->get_path_length + frc->bd->put_path_length)
+           * sizeof(struct GNUNET_DHT_PathElement);
+  if (truncated)
+    xsize += sizeof (struct GNUNET_PeerIdentity);
   env = GNUNET_MQ_msg_extra (reply,
-                             frc->bd->data_size
-                             + (frc->get_path_length + 
frc->bd->put_path_length)
-                             * sizeof(struct GNUNET_DHT_PathElement),
+                             xsize,
                              GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT);
   reply->type = htonl (frc->bd->type);
+  reply->options = htonl (bd->ro);
   reply->get_path_length = htonl (frc->get_path_length);
   reply->put_path_length = htonl (frc->bd->put_path_length);
   reply->unique_id = record->unique_id;
   reply->expiration = GNUNET_TIME_absolute_hton (frc->bd->expiration_time);
   reply->key = *query_hash;
-  paths = (struct GNUNET_DHT_PathElement *) &reply[1];
+  if (truncated)
+  {
+    void *tgt = &reply[1];
+
+    GNUNET_memcpy (tgt,
+                   &bd->trunc_peer,
+                   sizeof (struct GNUNET_PeerIdentity));
+    paths = (struct GNUNET_DHT_PathElement *)
+            (tgt + sizeof (struct GNUNET_PeerIdentity));
+  }
+  else
+  {
+    paths = (struct GNUNET_DHT_PathElement *) &reply[1];
+  }
   GNUNET_memcpy (paths,
                  frc->bd->put_path,
                  sizeof(struct GNUNET_DHT_PathElement)
@@ -1041,6 +1058,7 @@ GDS_CLIENTS_handle_reply (const struct 
GNUNET_DATACACHE_Block *bd,
                  + bd->data_size
                  + (get_path_length + bd->put_path_length)
                  * sizeof(struct GNUNET_DHT_PathElement);
+  bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
 
   if (msize >= GNUNET_MAX_MESSAGE_SIZE)
   {
@@ -1052,6 +1070,9 @@ GDS_CLIENTS_handle_reply (const struct 
GNUNET_DATACACHE_Block *bd,
       GNUNET_DHT_verify_path (bd->data,
                               bd->data_size,
                               bd->expiration_time,
+                              truncated
+                              ? &bd->trunc_peer
+                              : NULL,
                               bd->put_path,
                               bd->put_path_length,
                               get_path,
@@ -1291,27 +1312,30 @@ for_matching_monitors (enum GNUNET_BLOCK_Type type,
        NULL != m;
        m = m->next)
   {
-    if ( ( (GNUNET_BLOCK_TYPE_ANY == m->type) ||
-           (m->type == type) ) &&
-         ( (GNUNET_is_zero (&m->key)) ||
-           (0 ==
-            GNUNET_memcmp (key,
-                           &m->key)) ) )
-    {
-      unsigned int i;
-
-      /* Don't send duplicates */
-      for (i = 0; i < cl_size; i++)
-        if (cl[i] == m->ch)
-          break;
-      if (i < cl_size)
-        continue;
-      GNUNET_array_append (cl,
-                           cl_size,
-                           m->ch);
-      cb (cb_cls,
-          m);
-    }
+    bool found = false;
+
+    if ( (GNUNET_BLOCK_TYPE_ANY != m->type) &&
+         (m->type != type) )
+      continue;
+    if ( (! GNUNET_is_zero (&m->key)) &&
+         (0 ==
+          GNUNET_memcmp (key,
+                         &m->key)) )
+      continue;
+    /* Don't send duplicates */
+    for (unsigned i = 0; i < cl_size; i++)
+      if (cl[i] == m->ch)
+      {
+        found = true;
+        break;
+      }
+    if (found)
+      continue;
+    GNUNET_array_append (cl,
+                         cl_size,
+                         m->ch);
+    cb (cb_cls,
+        m);
   }
   GNUNET_free (cl);
 }
@@ -1326,8 +1350,7 @@ struct GetActionContext
   enum GNUNET_BLOCK_Type type;
   uint32_t hop_count;
   uint32_t desired_replication_level;
-  unsigned int get_path_length;
-  const struct GNUNET_DHT_PathElement *get_path;
+  struct GNUNET_PeerIdentity trunc_peer;
   const struct GNUNET_HashCode *key;
 };
 
@@ -1346,23 +1369,14 @@ get_action (void *cls,
   struct GetActionContext *gac = cls;
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_DHT_MonitorGetMessage *mmsg;
-  struct GNUNET_DHT_PathElement *msg_path;
-  size_t msize;
 
-  msize = gac->get_path_length * sizeof(struct GNUNET_DHT_PathElement);
-  env = GNUNET_MQ_msg_extra (mmsg,
-                             msize,
-                             GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET);
+  env = GNUNET_MQ_msg (mmsg,
+                       GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET);
   mmsg->options = htonl (gac->options);
   mmsg->type = htonl (gac->type);
   mmsg->hop_count = htonl (gac->hop_count);
   mmsg->desired_replication_level = htonl (gac->desired_replication_level);
-  mmsg->get_path_length = htonl (gac->get_path_length);
   mmsg->key = *gac->key;
-  msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
-  GNUNET_memcpy (msg_path,
-                 gac->get_path,
-                 gac->get_path_length * sizeof(struct GNUNET_DHT_PathElement));
   GNUNET_MQ_send (m->ch->mq,
                   env);
 }
@@ -1375,8 +1389,6 @@ get_action (void *cls,
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
- * @param path_length number of entries in path (or 0 if not recorded).
- * @param path peers on the GET path (or NULL if not recorded).
  * @param desired_replication_level Desired replication level.
  * @param key Key of the requested data.
  */
@@ -1385,8 +1397,6 @@ GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption 
options,
                          enum GNUNET_BLOCK_Type type,
                          uint32_t hop_count,
                          uint32_t desired_replication_level,
-                         unsigned int path_length,
-                         const struct GNUNET_DHT_PathElement *path,
                          const struct GNUNET_HashCode *key)
 {
   struct GetActionContext gac = {
@@ -1394,8 +1404,6 @@ GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption 
options,
     .type = type,
     .hop_count = hop_count,
     .desired_replication_level = desired_replication_level,
-    .get_path_length = path_length,
-    .get_path = path,
     .key = key
   };
 
@@ -1430,7 +1438,7 @@ response_action (void *cls,
 {
   const struct ResponseActionContext *resp_ctx = cls;
   const struct GNUNET_DATACACHE_Block *bd = resp_ctx->bd;
-
+  bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_DHT_MonitorGetRespMessage *mmsg;
   struct GNUNET_DHT_PathElement *path;
@@ -1439,6 +1447,8 @@ response_action (void *cls,
   msize = bd->data_size;
   msize += (resp_ctx->get_path_length + bd->put_path_length)
            * sizeof(struct GNUNET_DHT_PathElement);
+  if (truncated)
+    msize += sizeof (struct GNUNET_PeerIdentity);
   env = GNUNET_MQ_msg_extra (mmsg,
                              msize,
                              GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP);
@@ -1447,7 +1457,20 @@ response_action (void *cls,
   mmsg->get_path_length = htonl (resp_ctx->get_path_length);
   mmsg->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
   mmsg->key = bd->key;
-  path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
+  if (truncated)
+  {
+    void *tgt = &mmsg[1];
+
+    GNUNET_memcpy (tgt,
+                   &bd->trunc_peer,
+                   sizeof (struct GNUNET_PeerIdentity));
+    path = (struct GNUNET_DHT_PathElement *)
+           (tgt + sizeof (struct GNUNET_PeerIdentity));
+  }
+  else
+  {
+    path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
+  }
   GNUNET_memcpy (path,
                  bd->put_path,
                  bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
@@ -1505,6 +1528,7 @@ put_action (void *cls,
 {
   const struct PutActionContext *put_ctx = cls;
   const struct GNUNET_DATACACHE_Block *bd = put_ctx->bd;
+  bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_DHT_MonitorPutMessage *mmsg;
   struct GNUNET_DHT_PathElement *msg_path;
@@ -1513,6 +1537,8 @@ put_action (void *cls,
   msize = bd->data_size
           + bd->put_path_length
           * sizeof(struct GNUNET_DHT_PathElement);
+  if (truncated)
+    msize += sizeof (struct GNUNET_PeerIdentity);
   env = GNUNET_MQ_msg_extra (mmsg,
                              msize,
                              GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT);
@@ -1523,7 +1549,20 @@ put_action (void *cls,
   mmsg->put_path_length = htonl (bd->put_path_length);
   mmsg->key = bd->key;
   mmsg->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
-  msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
+  if (truncated)
+  {
+    void *tgt = &mmsg[1];
+
+    GNUNET_memcpy (tgt,
+                   &bd->trunc_peer,
+                   sizeof (struct GNUNET_PeerIdentity));
+    msg_path = (struct GNUNET_DHT_PathElement *)
+               (tgt + sizeof (struct GNUNET_PeerIdentity));
+  }
+  else
+  {
+    msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
+  }
   GNUNET_memcpy (msg_path,
                  bd->put_path,
                  bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
diff --git a/src/dht/gnunet-service-dht_neighbours.c 
b/src/dht/gnunet-service-dht_neighbours.c
index 2a54f715a..cc7333a9c 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.c
@@ -150,8 +150,12 @@ struct PeerPutMessage
    */
   struct GNUNET_HashCode key;
 
+  /* trunc_peer (if truncated) */
+
   /* put path (if tracked) */
 
+  /* sender_sig (if path tracking is on) */
+
   /* Payload */
 };
 
@@ -172,9 +176,9 @@ struct PeerResultMessage
   uint32_t type GNUNET_PACKED;
 
   /**
-   * Reserved.
+   * Message options, actually an 'enum GNUNET_DHT_RouteOption' value in NBO.
    */
-  uint32_t reserved GNUNET_PACKED;
+  uint32_t options GNUNET_PACKED;
 
   /**
    * Length of the PUT path that follows (if tracked).
@@ -196,10 +200,14 @@ struct PeerResultMessage
    */
   struct GNUNET_HashCode key;
 
+  /* trunc_peer (if truncated) */
+
   /* put path (if tracked) */
 
   /* get path (if tracked) */
 
+  /* sender_sig (if path tracking is on) */
+
   /* Payload */
 };
 
@@ -537,10 +545,11 @@ sign_path (const void *data,
     .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
     .purpose.size = htonl (sizeof (hs)),
     .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
-    .pred = *pred,
     .succ = *succ
   };
 
+  if (NULL != pred)
+    hs.pred = *pred;
   GNUNET_CRYPTO_hash (data,
                       data_size,
                       &hs.h_data);
@@ -1314,21 +1323,36 @@ GDS_NEIGHBOURS_handle_put (const struct 
GNUNET_DATACACHE_Block *bd,
   struct PeerInfo **targets;
   size_t msize;
   unsigned int skip_count;
+  enum GNUNET_DHT_RouteOption ro = bd->ro;
   unsigned int put_path_length = bd->put_path_length;
+  const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? &bd->trunc_peer
+    : NULL;
 
-  GNUNET_assert (NULL != bf);
 #if SANITY_CHECKS > 1
-  if (0 !=
-      GNUNET_DHT_verify_path (bd->data,
+  unsigned int failure_offset;
+
+  failure_offset
+    = GNUNET_DHT_verify_path (bd->data,
                               bd->data_size,
                               bd->expiration_time,
-                              bd->put_path,
-                              bd->put_path_length,
-                              NULL, 0, /* get_path */
-                              &GDS_my_identity))
+                              trunc_peer,
+                              put_path,
+                              put_path_length,
+                              NULL, 0,    /* get_path */
+                              &GDS_my_identity);
+  if (0 != failure_offset)
   {
     GNUNET_break_op (0);
-    put_path_length = 0;
+    truncated = true;
+    trunc_peer = &put_path[failure_offset - 1].pred;
+    put_path = &put_path[failure_offset];
+    put_path_length = put_path_length - failure_offset;
+    ro |= GNUNET_DHT_RO_TRUNCATED;
   }
 #endif
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1340,12 +1364,70 @@ GDS_NEIGHBOURS_handle_put (const struct 
GNUNET_DATACACHE_Block *bd,
 
   /* if we got a HELLO, consider it for our own routing table */
   hello_check (bd);
+  GNUNET_assert (NULL != bf);
   GNUNET_CONTAINER_bloomfilter_add (bf,
                                     &GDS_my_identity_hash);
   GNUNET_STATISTICS_update (GDS_stats,
                             "# PUT requests routed",
                             1,
                             GNUNET_NO);
+  if (bd->data_size
+      > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
+      - sizeof(struct PeerPutMessage))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  msize = bd->data_size + sizeof(struct PeerPutMessage);
+  if (tracking)
+  {
+    if (msize + sizeof (struct GNUNET_CRYPTO_EddsaSignature)
+        > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Discarding message that is too large due to tracking\n");
+      return GNUNET_NO;
+    }
+    msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
+  }
+  else
+  {
+    /* If tracking is disabled, also discard any path we might have
+       gotten from some broken peer */
+    GNUNET_break_op (0 == put_path_length);
+    put_path_length = 0;
+  }
+  if (truncated)
+    msize += sizeof (struct GNUNET_PeerIdentity);
+  if (msize + put_path_length * sizeof(struct GNUNET_DHT_PathElement)
+      > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
+  {
+    unsigned int mlen;
+    unsigned int ppl;
+
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Truncating path that is too large due\n");
+    mlen = GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE - msize;
+    if (! truncated)
+    {
+      /* We need extra space for the truncation, consider that,
+         too! */
+      truncated = true;
+      mlen -= sizeof (struct GNUNET_PeerIdentity);
+      msize += sizeof (struct GNUNET_PeerIdentity);
+    }
+    /* compute maximum length of path we can keep */
+    ppl = mlen / sizeof (struct GNUNET_DHT_PathElement);
+    GNUNET_assert (put_path_length - ppl > 0);
+    trunc_peer = &put_path[put_path_length - ppl - 1].pred;
+    put_path = &put_path[put_path_length - ppl];
+    put_path_length = ppl;
+    ro |= GNUNET_DHT_RO_TRUNCATED;
+  }
+  else
+  {
+    msize += bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement);
+  }
   target_count
     = get_target_peers (&bd->key,
                         bf,
@@ -1361,28 +1443,14 @@ GDS_NEIGHBOURS_handle_put (const struct 
GNUNET_DATACACHE_Block *bd,
                 GNUNET_i2s (&GDS_my_identity));
     return GNUNET_NO;
   }
-  msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement)
-          + bd->data_size;
-  if (msize + sizeof(struct PeerPutMessage)
-      >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
-  {
-    put_path_length = 0;
-    msize = bd->data_size;
-  }
-  if (msize + sizeof(struct PeerPutMessage)
-      >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
-  {
-    GNUNET_break (0);
-    GNUNET_free (targets);
-    return GNUNET_NO;
-  }
   skip_count = 0;
   for (unsigned int i = 0; i < target_count; i++)
   {
     struct PeerInfo *target = targets[i];
     struct PeerPutMessage *ppm;
-    char buf[sizeof (*ppm) + msize] GNUNET_ALIGN;
+    char buf[msize] GNUNET_ALIGN;
     struct GNUNET_DHT_PathElement *pp;
+    void *data;
 
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Routing PUT for %s after %u hops to %s\n",
@@ -1393,7 +1461,7 @@ GDS_NEIGHBOURS_handle_put (const struct 
GNUNET_DATACACHE_Block *bd,
     ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
     ppm->header.size = htons (sizeof (buf));
     ppm->type = htonl (bd->type);
-    ppm->options = htons (bd->ro);
+    ppm->options = htons (ro);
     ppm->hop_count = htons (hop_count + 1);
     ppm->desired_replication_level = htons (desired_replication_level);
     ppm->put_path_length = htons (put_path_length);
@@ -1406,28 +1474,62 @@ GDS_NEIGHBOURS_handle_put (const struct 
GNUNET_DATACACHE_Block *bd,
                                                               ppm->bloomfilter,
                                                               DHT_BLOOM_SIZE));
     ppm->key = bd->key;
-    pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
+    if (truncated)
+    {
+      void *tgt = &ppm[1];
+
+      GNUNET_memcpy (tgt,
+                     trunc_peer,
+                     sizeof (struct GNUNET_PeerIdentity));
+      pp = (struct GNUNET_DHT_PathElement *)
+           (tgt + sizeof (struct GNUNET_PeerIdentity));
+    }
+    else
+    {
+      pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
+    }
     GNUNET_memcpy (pp,
-                   bd->put_path,
+                   put_path,
                    sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
-    /* 0 == put_path_length means path is not being tracked */
-    if (0 != put_path_length)
+    if (tracking)
     {
-      /* Note that the signature in 'put_path' was not initialized before,
-         so this is crucial to avoid sending garbage. */
-      sign_path (bd->data,
-                 bd->data_size,
-                 bd->expiration_time,
-                 &pp[put_path_length - 1].pred,
-                 &target->id,
-                 &pp[put_path_length - 1].sig);
+      void *tgt = &pp[put_path_length];
+      struct GNUNET_CRYPTO_EddsaSignature last_sig;
+
+      if (0 == put_path_length)
+      {
+        /* Note that the signature in 'put_path' was not initialized before,
+           so this is crucial to avoid sending garbage. */
+        sign_path (bd->data,
+                   bd->data_size,
+                   bd->expiration_time,
+                   trunc_peer,
+                   &target->id,
+                   &last_sig);
+      }
+      else
+      {
+        sign_path (bd->data,
+                   bd->data_size,
+                   bd->expiration_time,
+                   &pp[put_path_length - 1].pred,
+                   &target->id,
+                   &last_sig);
+      }
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Signing PUT PATH %u => %s\n",
                   put_path_length,
-                  GNUNET_B2S (&pp[put_path_length - 1].sig));
+                  GNUNET_B2S (&last_sig));
+      memcpy (tgt,
+              &last_sig,
+              sizeof (last_sig));
+      data = tgt + sizeof (last_sig);
     }
-
-    GNUNET_memcpy (&pp[put_path_length],
+    else /* ! tracking */
+    {
+      data = &ppm[1];
+    }
+    GNUNET_memcpy (data,
                    bd->data,
                    bd->data_size);
     do_send (target,
@@ -1572,46 +1674,86 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
   struct GNUNET_DHT_PathElement *paths;
   size_t msize;
   unsigned int ppl = bd->put_path_length;
-
+  const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
+  enum GNUNET_DHT_RouteOption ro = bd->ro;
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? &bd->trunc_peer
+    : NULL;
+  bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
 #if SANITY_CHECKS > 1
-  if (0 !=
-      GNUNET_DHT_verify_path (bd->data,
+  unsigned int failure_offset;
+
+  failure_offset
+    = GNUNET_DHT_verify_path (bd->data,
                               bd->data_size,
                               bd->expiration_time,
-                              bd->put_path,
-                              bd->put_path_length,
+                              trunc_peer,
+                              put_path,
+                              ppl,
                               get_path,
                               get_path_length,
-                              &GDS_my_identity))
+                              &GDS_my_identity);
+  if (0 != failure_offset)
   {
+    GNUNET_assert (failure_offset <= ppl + get_path_length);
     GNUNET_break_op (0);
-    return false;
+    if (failure_offset < ppl)
+    {
+      trunc_peer = &put_path[failure_offset - 1].pred;
+      put_path += failure_offset;
+      ppl -= failure_offset;
+      truncated = true;
+      ro |= GNUNET_DHT_RO_TRUNCATED;
+    }
+    else
+    {
+      failure_offset -= ppl;
+      if (0 == failure_offset)
+        trunc_peer = &put_path[ppl - 1].pred;
+      else
+        trunc_peer = &get_path[failure_offset - 1].pred;
+      ppl = 0;
+      put_path = NULL;
+      truncated = true;
+      ro |= GNUNET_DHT_RO_TRUNCATED;
+      get_path += failure_offset;
+      get_path_length -= failure_offset;
+    }
   }
 #endif
-  msize = bd->data_size + (get_path_length + ppl)
-          * sizeof(struct GNUNET_DHT_PathElement);
-  if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
-       (get_path_length >
-        GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
-       (ppl >
-        GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
-       (bd->data_size > GNUNET_MAX_MESSAGE_SIZE))
+  msize = bd->data_size + sizeof (struct PeerResultMessage);
+  if (msize > GNUNET_MAX_MESSAGE_SIZE)
+  {
+    GNUNET_break_op (0);
+    return false;
+  }
+  if (truncated)
+    msize += sizeof (struct GNUNET_PeerIdentity);
+  if (tracking)
+    msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
+  if (msize < bd->data_size)
+  {
+    GNUNET_break_op (0);
+    return false;
+  }
+  if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
+       / sizeof(struct GNUNET_DHT_PathElement)
+       < (get_path_length + ppl) )
   {
-    ppl = 0;
     get_path_length = 0;
-    msize = bd->data_size + (get_path_length + ppl)
-            * sizeof(struct GNUNET_DHT_PathElement);
+    ppl = 0;
   }
-  if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
-       (get_path_length >
-        GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
-       (ppl >
-        GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
-       (bd->data_size > GNUNET_MAX_MESSAGE_SIZE))
+  if ( (get_path_length > UINT16_MAX) ||
+       (ppl > UINT16_MAX) )
   {
     GNUNET_break (0);
-    return false;
+    get_path_length = 0;
+    ppl = 0;
   }
+  msize += (get_path_length + ppl)
+           * sizeof(struct GNUNET_DHT_PathElement);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Forwarding reply for key %s to peer %s\n",
               GNUNET_h2s (query_hash),
@@ -1622,22 +1764,36 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
                             GNUNET_NO);
   {
     struct PeerResultMessage *prm;
-    char buf[sizeof (*prm) + msize] GNUNET_ALIGN;
+    char buf[msize] GNUNET_ALIGN;
+    void *data;
 
     prm = (struct PeerResultMessage *) buf;
     prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
     prm->header.size = htons (sizeof (buf));
-    prm->type = htonl (bd->type);
-    prm->reserved = htonl (0);
-    prm->put_path_length = htons (ppl);
-    prm->get_path_length = htons (get_path_length);
+    prm->type = htonl ((uint32_t) bd->type);
+    prm->options = htonl ((uint32_t) ro);
+    prm->put_path_length = htons ((uint16_t) ppl);
+    prm->get_path_length = htons ((uint16_t) get_path_length);
     prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
     prm->key = *query_hash;
-    paths = (struct GNUNET_DHT_PathElement *) &prm[1];
-    if (NULL != bd->put_path)
+    if (truncated)
+    {
+      void *tgt = &prm[1];
+
+      GNUNET_memcpy (tgt,
+                     trunc_peer,
+                     sizeof (struct GNUNET_PeerIdentity));
+      paths = (struct GNUNET_DHT_PathElement *)
+              (tgt + sizeof (struct GNUNET_PeerIdentity));
+    }
+    else
+    {
+      paths = (struct GNUNET_DHT_PathElement *) &prm[1];
+    }
+    if (NULL != put_path)
     {
       GNUNET_memcpy (paths,
-                     bd->put_path,
+                     put_path,
                      ppl * sizeof(struct GNUNET_DHT_PathElement));
     }
     else
@@ -1654,51 +1810,69 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
     {
       GNUNET_assert (0 == get_path_length);
     }
-    /* 0 == get_path_length+ppl means path is not being tracked */
-    if (0 != (get_path_length + ppl))
+    if (tracking)
     {
+      struct GNUNET_CRYPTO_EddsaSignature sig;
+      void *tgt = &paths[get_path_length + ppl];
+      const struct GNUNET_PeerIdentity *pred;
+
+      if (ppl + get_path_length > 0)
+        pred = &paths[ppl + get_path_length - 1].pred;
+      else if (truncated)
+        pred = trunc_peer;
+      else
+        pred = NULL; /* we are first! */
       /* Note that the last signature in 'paths' was not initialized before,
          so this is crucial to avoid sending garbage. */
       sign_path (bd->data,
                  bd->data_size,
                  bd->expiration_time,
-                 &paths[ppl + get_path_length - 1].pred,
+                 pred,
                  &pi->id,
-                 &paths[ppl + get_path_length - 1].sig);
+                 &sig);
+      memcpy (tgt,
+              &sig,
+              sizeof (sig));
+      data = tgt + sizeof (sig);
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Signing GET PATH %u/%u of %s => %s\n",
                   ppl,
                   get_path_length,
                   GNUNET_h2s (query_hash),
-                  GNUNET_B2S (&paths[ppl + get_path_length - 1].sig));
-    }
-    GNUNET_memcpy (&paths[ppl + get_path_length],
-                   bd->data,
-                   bd->data_size);
-
+                  GNUNET_B2S (&sig));
 #if SANITY_CHECKS > 1
-    {
-      struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
-
-      memcpy (xpaths,
-              &paths[ppl],
-              get_path_length * sizeof (struct GNUNET_DHT_PathElement));
-      xpaths[get_path_length].pred = GDS_my_identity;
-      if (0 !=
-          GNUNET_DHT_verify_path (bd->data,
-                                  bd->data_size,
-                                  bd->expiration_time,
-                                  paths,
-                                  ppl,
-                                  xpaths,
-                                  get_path_length + 1,
-                                  &pi->id))
       {
-        GNUNET_break (0);
-        return false;
+        struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
+
+        memcpy (xpaths,
+                &paths[ppl],
+                get_path_length * sizeof (struct GNUNET_DHT_PathElement));
+        xpaths[get_path_length].sig = sig;
+        xpaths[get_path_length].pred = GDS_my_identity;
+        if (0 !=
+            GNUNET_DHT_verify_path (bd->data,
+                                    bd->data_size,
+                                    bd->expiration_time,
+                                    trunc_peer,
+                                    paths,
+                                    ppl,
+                                    xpaths,
+                                    get_path_length + 1,
+                                    &pi->id))
+        {
+          GNUNET_break (0);
+          return false;
+        }
       }
-    }
 #endif
+    }
+    else
+    {
+      data = &prm[1];
+    }
+    GNUNET_memcpy (data,
+                   bd->data,
+                   bd->data_size);
     do_send (pi,
              &prm->header);
   }
@@ -1717,15 +1891,30 @@ static enum GNUNET_GenericReturnValue
 check_dht_p2p_put (void *cls,
                    const struct PeerPutMessage *put)
 {
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
   uint16_t msize = ntohs (put->header.size);
   uint16_t putlen = ntohs (put->put_path_length);
+  size_t xsize = (has_path
+                  ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
+                  : 0)
+                 + (truncated
+                    ? sizeof (struct GNUNET_PeerIdentity)
+                    : 0);
+  size_t var_meta_size
+    = putlen * sizeof(struct GNUNET_DHT_PathElement)
+      + xsize;
 
   (void) cls;
   if ( (msize <
-        sizeof(struct PeerPutMessage)
-        + putlen * sizeof(struct GNUNET_DHT_PathElement)) ||
+        sizeof (struct PeerPutMessage) + var_meta_size) ||
        (putlen >
-        GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
+        (GNUNET_MAX_MESSAGE_SIZE
+         - sizeof (struct PeerPutMessage)
+         - xsize)
+        / sizeof(struct GNUNET_DHT_PathElement)) )
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
@@ -1746,27 +1935,49 @@ handle_dht_p2p_put (void *cls,
 {
   struct Target *t = cls;
   struct PeerInfo *peer = t->pi;
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
   uint16_t msize = ntohs (put->header.size);
+  uint16_t putlen = ntohs (put->put_path_length);
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? (const struct GNUNET_PeerIdentity *) &put[1]
+    : NULL;
   const struct GNUNET_DHT_PathElement *put_path
-    = (const struct GNUNET_DHT_PathElement *) &put[1];
-  uint16_t putlen
-    = ntohs (put->put_path_length);
+    = truncated
+    ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
+    : (const struct GNUNET_DHT_PathElement *) &put[1];
+  const struct GNUNET_CRYPTO_EddsaSignature *last_sig
+    = has_path
+    ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
+    : NULL;
+  const char *data
+    = has_path
+    ? (const char *) &last_sig[1]
+    : (const char *) &put_path[putlen];
+  size_t var_meta_size
+    = putlen * sizeof(struct GNUNET_DHT_PathElement)
+      + has_path ? sizeof (*last_sig) : 0
+      + truncated ? sizeof (*trunc_peer) : 0;
   struct GNUNET_DATACACHE_Block bd = {
     .key = put->key,
     .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
     .type = ntohl (put->type),
-    .ro = (enum GNUNET_DHT_RouteOption) ntohs (put->options),
-    .data_size = msize - (sizeof(*put)
-                          + putlen * sizeof(struct GNUNET_DHT_PathElement)),
-    .data = &put_path[putlen]
+    .ro = ro,
+    .data_size = msize - sizeof(*put) - var_meta_size,
+    .data = data
   };
 
+  if (NULL != trunc_peer)
+    bd.trunc_peer = *trunc_peer;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "PUT for `%s' from %s with RO (%s/%s)\n",
               GNUNET_h2s (&put->key),
               GNUNET_i2s (&peer->id),
               (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
-              (bd.ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
+              has_path ? "R" : "-");
   if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
   {
     GNUNET_STATISTICS_update (GDS_stats,
@@ -1784,7 +1995,7 @@ handle_dht_p2p_put (void *cls,
     GNUNET_break_op (0);
     return;
   }
-  if (0 == (bd.ro & GNUNET_DHT_RO_RECORD_ROUTE))
+  if (! has_path)
     putlen = 0;
   GNUNET_STATISTICS_update (GDS_stats,
                             "# P2P PUT requests received",
@@ -1835,7 +2046,7 @@ handle_dht_p2p_put (void *cls,
     /* extend 'put path' by sender */
     bd.put_path = (const struct GNUNET_DHT_PathElement *) pp;
     bd.put_path_length = putlen + 1;
-    if (0 != (bd.ro & GNUNET_DHT_RO_RECORD_ROUTE))
+    if (has_path)
     {
       unsigned int failure_offset;
 
@@ -1843,10 +2054,7 @@ handle_dht_p2p_put (void *cls,
                      put_path,
                      putlen * sizeof(struct GNUNET_DHT_PathElement));
       pp[putlen].pred = peer->id;
-      /* zero-out signature, not valid until we actually do forward! */
-      memset (&pp[putlen].sig,
-              0,
-              sizeof (pp[putlen].sig));
+      pp[putlen].sig = *last_sig;
 #if SANITY_CHECKS
       /* TODO: might want to eventually implement probabilistic
          load-based path verification, but for now it is all or nothing */
@@ -1854,6 +2062,7 @@ handle_dht_p2p_put (void *cls,
         = GNUNET_DHT_verify_path (bd.data,
                                   bd.data_size,
                                   bd.expiration_time,
+                                  trunc_peer,
                                   pp,
                                   putlen + 1,
                                   NULL, 0,   /* get_path */
@@ -1863,12 +2072,15 @@ handle_dht_p2p_put (void *cls,
 #endif
       if (0 != failure_offset)
       {
+        GNUNET_break_op (0);
         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                     "Recorded put path invalid at offset %u, truncating\n",
                     failure_offset);
-        GNUNET_assert (failure_offset <= putlen);
+        GNUNET_assert (failure_offset <= putlen + 1);
         bd.put_path = &pp[failure_offset];
         bd.put_path_length = putlen - failure_offset;
+        bd.ro |= GNUNET_DHT_RO_TRUNCATED;
+        bd.trunc_peer = pp[failure_offset - 1].pred;
       }
     }
     else
@@ -2218,8 +2430,6 @@ handle_dht_p2p_get (void *cls,
         type,
         hop_count,
         desired_replication_level,
-        0,
-        NULL,
         &get->key);
     }
     /* clean up; note that 'bg' is owned by routing now! */
@@ -2326,17 +2536,44 @@ handle_dht_p2p_result (void *cls,
 {
   struct Target *t = cls;
   struct PeerInfo *peer = t->pi;
-  uint16_t msize = ntohs (prm->header.size);
+  uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
+  enum GNUNET_DHT_RouteOption ro
+    = (enum GNUNET_DHT_RouteOption) ntohl (prm->options);
+  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
+  bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
   uint16_t get_path_length = ntohs (prm->get_path_length);
+  uint16_t put_path_length = ntohs (prm->put_path_length);
+  const struct GNUNET_PeerIdentity *trunc_peer
+    = truncated
+    ? (const struct GNUNET_PeerIdentity *) &prm[1]
+    : NULL;
+  const struct GNUNET_DHT_PathElement *put_path
+    = truncated
+    ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
+    : (const struct GNUNET_DHT_PathElement *) &prm[1];
+  const struct GNUNET_DHT_PathElement *get_path
+    = &put_path[put_path_length];
+  const struct GNUNET_CRYPTO_EddsaSignature *last_sig
+    = tracked
+    ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
+    : NULL;
+  const void *data
+    = tracked
+    ? (const void *) &last_sig[1]
+    : (const void *) &get_path[get_path_length];
+  size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
+                 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 
0);
   struct GNUNET_DATACACHE_Block bd = {
     .expiration_time  = GNUNET_TIME_absolute_ntoh (prm->expiration_time),
-    .put_path = (const struct GNUNET_DHT_PathElement *) &prm[1],
-    .put_path_length = ntohs (prm->put_path_length),
+    .put_path = put_path,
+    .put_path_length = put_path_length,
     .key = prm->key,
-    .type = ntohl (prm->type)
+    .type = ntohl (prm->type),
+    .ro = ro,
+    .data = data,
+    .data_size = msize - vsize - (get_path_length + put_path_length)
+                 * sizeof(struct GNUNET_DHT_PathElement)
   };
-  const struct GNUNET_DHT_PathElement *get_path
-    = &bd.put_path[bd.put_path_length];
 
   /* parse and validate message */
   if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
@@ -2347,11 +2584,6 @@ handle_dht_p2p_result (void *cls,
                               GNUNET_NO);
     return;
   }
-  get_path = &bd.put_path[bd.put_path_length];
-  bd.data = (const void *) &get_path[get_path_length];
-  bd.data_size = msize - (sizeof(struct PeerResultMessage)
-                          + (get_path_length + bd.put_path_length)
-                          * sizeof(struct GNUNET_DHT_PathElement));
   if (GNUNET_OK !=
       GNUNET_BLOCK_check_block (GDS_block_context,
                                 bd.type,
@@ -2385,6 +2617,7 @@ handle_dht_p2p_result (void *cls,
   hello_check (&bd);
 
   /* Need to append 'peer' to 'get_path' */
+  if (tracked)
   {
     struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
     struct GNUNET_DHT_PathElement *gp = xget_path;
@@ -2394,9 +2627,10 @@ handle_dht_p2p_result (void *cls,
                    get_path,
                    get_path_length * sizeof(struct GNUNET_DHT_PathElement));
     xget_path[get_path_length].pred = peer->id;
-    memset (&xget_path[get_path_length].sig,
-            0,
-            sizeof (xget_path[get_path_length].sig));
+    /* use memcpy(), as last_sig may not be aligned */
+    memcpy (&xget_path[get_path_length].sig,
+            last_sig,
+            sizeof (*last_sig));
 #if SANITY_CHECKS
     /* TODO: might want to eventually implement probabilistic
        load-based path verification, but for now it is all or nothing */
@@ -2404,9 +2638,10 @@ handle_dht_p2p_result (void *cls,
       = GNUNET_DHT_verify_path (bd.data,
                                 bd.data_size,
                                 bd.expiration_time,
-                                bd.put_path,
-                                bd.put_path_length,
-                                xget_path,
+                                trunc_peer,
+                                put_path,
+                                put_path_length,
+                                gp,
                                 get_path_length + 1,
                                 &GDS_my_identity);
 #else
@@ -2417,30 +2652,59 @@ handle_dht_p2p_result (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   "Recorded path invalid at offset %u, truncating\n",
                   failure_offset);
-      GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length);
-      if (failure_offset >= bd.put_path_length)
-      {
-        /* failure on get path */
-        get_path_length -= (failure_offset - bd.put_path_length);
-        gp = &xget_path[failure_offset - bd.put_path_length];
-        bd.put_path_length = 0;
-      }
-      else
+      GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
+                     + 1);
+      if (failure_offset < bd.put_path_length)
       {
         /* failure on put path */
+        trunc_peer = &bd.put_path[failure_offset - 1].pred;
+        bd.ro |= GNUNET_DHT_RO_TRUNCATED;
         bd.put_path = &bd.put_path[failure_offset];
         bd.put_path_length -= failure_offset;
+        truncated = true;
+      }
+      else
+      {
+        /* failure on get path */
+        failure_offset -= bd.put_path_length;
+        if (0 == failure_offset)
+          trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
+        else
+          trunc_peer = &gp[failure_offset - 1].pred;
+        get_path_length -= failure_offset;
+        gp = &gp[failure_offset];
+        bd.put_path_length = 0;
+        bd.put_path = NULL;
+        bd.ro |= GNUNET_DHT_RO_TRUNCATED;
+        truncated = true;
       }
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Extending GET path of length %u with %s\n",
                 get_path_length,
                 GNUNET_i2s (&peer->id));
+    if (truncated)
+    {
+      GNUNET_assert (NULL != trunc_peer);
+      bd.trunc_peer = *trunc_peer;
+    }
     GNUNET_break (process_reply_with_path (&bd,
                                            &prm->key,
                                            get_path_length + 1,
                                            gp));
   }
+  else
+  {
+    if (truncated)
+    {
+      GNUNET_assert (NULL != trunc_peer);
+      bd.trunc_peer = *trunc_peer;
+    }
+    GNUNET_break (process_reply_with_path (&bd,
+                                           &prm->key,
+                                           0,
+                                           NULL));
+  }
 }
 
 
diff --git a/src/dht/gnunet_dht_profiler.c b/src/dht/gnunet_dht_profiler.c
index bac101bdd..55a34bdf0 100644
--- a/src/dht/gnunet_dht_profiler.c
+++ b/src/dht/gnunet_dht_profiler.c
@@ -455,6 +455,7 @@ cancel_get (void *cls)
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer peer the path was truncated at, or NULL
  * @param get_path peers on reply path (or NULL if not recorded)
  *                 [0] = datastore's first neighbor, [length - 1] = local peer
  * @param get_path_length number of entries in @a get_path
@@ -469,12 +470,14 @@ static void
 get_iter (void *cls,
           struct GNUNET_TIME_Absolute exp,
           const struct GNUNET_HashCode *key,
+          const struct GNUNET_PeerIdentity *trunc_peer,
           const struct GNUNET_DHT_PathElement *get_path,
           unsigned int get_path_length,
           const struct GNUNET_DHT_PathElement *put_path,
           unsigned int put_path_length,
           enum GNUNET_BLOCK_Type type,
-          size_t size, const void *data)
+          size_t size,
+          const void *data)
 {
   struct ActiveContext *ac = cls;
   struct ActiveContext *get_ac = ac->get_ac;
diff --git a/src/dht/test_dht_api.c b/src/dht/test_dht_api.c
index 4d557bba8..044983b7e 100644
--- a/src/dht/test_dht_api.c
+++ b/src/dht/test_dht_api.c
@@ -87,6 +87,7 @@ static void
 test_get_iterator (void *cls,
                    struct GNUNET_TIME_Absolute exp,
                    const struct GNUNET_HashCode *key,
+                   const struct GNUNET_PeerIdentity *trunc_peer,
                    const struct GNUNET_DHT_PathElement *get_path,
                    unsigned int get_path_length,
                    const struct GNUNET_DHT_PathElement *put_path,
diff --git a/src/dht/test_dht_monitor.c b/src/dht/test_dht_monitor.c
index 8af02ad8a..3960a2235 100644
--- a/src/dht/test_dht_monitor.c
+++ b/src/dht/test_dht_monitor.c
@@ -163,6 +163,7 @@ timeout_task_cb (void *cls)
  * @param cls closure with our 'struct GetOperation'
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer peer the path was truncated at, or NULL
  * @param get_path peers on reply path (or NULL if not recorded)
  * @param get_path_length number of entries in get_path
  * @param put_path peers on the PUT path (or NULL if not recorded)
@@ -174,6 +175,7 @@ timeout_task_cb (void *cls)
 static void
 dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                  const struct GNUNET_HashCode *key,
+                 const struct GNUNET_PeerIdentity *trunc_peer,
                  const struct GNUNET_DHT_PathElement *get_path,
                  unsigned int get_path_length,
                  const struct GNUNET_DHT_PathElement *put_path,
@@ -189,7 +191,9 @@ dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
     GNUNET_break (0);
     return;
   }
-  GNUNET_CRYPTO_hash (key, sizeof(*key), &want);
+  GNUNET_CRYPTO_hash (key,
+                      sizeof(*key),
+                      &want);
   if (0 != memcmp (&want, data, sizeof(want)))
   {
     GNUNET_break (0);
@@ -249,8 +253,6 @@ do_puts (void *cls)
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
- * @param path_length number of entries in path (or 0 if not recorded).
- * @param path peers on the GET path (or NULL if not recorded).
  * @param desired_replication_level Desired replication level.
  * @param key Key of the requested data.
  */
@@ -260,8 +262,6 @@ monitor_get_cb (void *cls,
                 enum GNUNET_BLOCK_Type type,
                 uint32_t hop_count,
                 uint32_t desired_replication_level,
-                unsigned int path_length,
-                const struct GNUNET_DHT_PathElement *path,
                 const struct GNUNET_HashCode *key)
 {
   unsigned int i;
@@ -283,6 +283,7 @@ monitor_get_cb (void *cls,
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
+ * @param trunc_peer peer the path was truncated at, or NULL
  * @param path_length number of entries in path (or 0 if not recorded).
  * @param path peers on the PUT path (or NULL if not recorded).
  * @param desired_replication_level Desired replication level.
@@ -297,6 +298,7 @@ monitor_put_cb (void *cls,
                 enum GNUNET_BLOCK_Type type,
                 uint32_t hop_count,
                 uint32_t desired_replication_level,
+                const struct GNUNET_PeerIdentity *trunc_peer,
                 unsigned int path_length,
                 const struct GNUNET_DHT_PathElement *path,
                 struct GNUNET_TIME_Absolute exp,
@@ -322,6 +324,7 @@ monitor_put_cb (void *cls,
  *
  * @param cls Closure.
  * @param type The type of data in the result.
+ * @param trunc_peer peer the path was truncated at, or NULL
  * @param get_path Peers on GET path (or NULL if not recorded).
  * @param get_path_length number of entries in get_path.
  * @param put_path peers on the PUT path (or NULL if not recorded).
@@ -334,6 +337,7 @@ monitor_put_cb (void *cls,
 static void
 monitor_res_cb (void *cls,
                 enum GNUNET_BLOCK_Type type,
+                const struct GNUNET_PeerIdentity *trunc_peer,
                 const struct GNUNET_DHT_PathElement *get_path,
                 unsigned int get_path_length,
                 const struct GNUNET_DHT_PathElement *put_path,
diff --git a/src/dht/test_dht_topo.c b/src/dht/test_dht_topo.c
index 4830ba629..a8294c65d 100644
--- a/src/dht/test_dht_topo.c
+++ b/src/dht/test_dht_topo.c
@@ -327,6 +327,7 @@ timeout_cb (void *cls)
  * @param cls closure with our 'struct GetOperation'
  * @param exp when will this value expire
  * @param query query hash
+ * @param trunc_peer peer the path was truncated at, or NULL
  * @param get_path peers on reply path (or NULL if not recorded)
  * @param get_path_length number of entries in @a get_path
  * @param put_path peers on the PUT path (or NULL if not recorded)
@@ -339,6 +340,7 @@ static void
 dht_get_handler (void *cls,
                  struct GNUNET_TIME_Absolute exp,
                  const struct GNUNET_HashCode *query,
+                 const struct GNUNET_PeerIdentity *trunc_peer,
                  const struct GNUNET_DHT_PathElement *get_path,
                  unsigned int get_path_length,
                  const struct GNUNET_DHT_PathElement *put_path,
@@ -380,6 +382,7 @@ dht_get_handler (void *cls,
       GNUNET_DHT_verify_path (data,
                               size,
                               exp,
+                              trunc_peer,
                               put_path,
                               put_path_length,
                               get_path,
diff --git a/src/fs/gnunet-service-fs_pr.c b/src/fs/gnunet-service-fs_pr.c
index f05194907..ee2dbca32 100644
--- a/src/fs/gnunet-service-fs_pr.c
+++ b/src/fs/gnunet-service-fs_pr.c
@@ -1077,6 +1077,7 @@ test_put_load_too_high (uint32_t priority)
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer truncated peer, NULL for none
  * @param get_path peers on reply path (or NULL if not recorded)
  * @param get_path_length number of entries in @a get_path
  * @param put_path peers on the PUT path (or NULL if not recorded)
@@ -1089,6 +1090,7 @@ static void
 handle_dht_reply (void *cls,
                   struct GNUNET_TIME_Absolute exp,
                   const struct GNUNET_HashCode *key,
+                  const struct GNUNET_PeerIdentity *trunc_peer,
                   const struct GNUNET_DHT_PathElement *get_path,
                   unsigned int get_path_length,
                   const struct GNUNET_DHT_PathElement *put_path,
diff --git a/src/gns/gnunet-service-gns_resolver.c 
b/src/gns/gnunet-service-gns_resolver.c
index 9d26e1777..0d844bc2e 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -1335,7 +1335,6 @@ handle_gns_redirect_result (struct GNS_ResolverHandle *rh,
 }
 
 
-
 /**
  * We encountered a CNAME record during our resolution.
  * Merge it into our chain.
@@ -1392,7 +1391,6 @@ handle_gns_resolution_result (void *cls,
                               const struct GNUNET_GNSRECORD_Data *rd);
 
 
-
 /**
  * We have resolved one or more of the nameservers for a
  * GNS2DNS lookup.  Once we have some of them, begin using
@@ -1592,6 +1590,7 @@ handle_gns2dns_ip (void *cls,
     ac->authority_info.dns_authority.found = GNUNET_YES;
 }
 
+
 /**
  * We found a REDIRECT record, perform recursive resolution on it.
  *
@@ -2329,7 +2328,7 @@ handle_gns_resolution_result (void *cls,
                 _ ("Unable to process critical delegation record\n"));
     break;
   }
-  fail:
+fail:
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
               _ ("GNS lookup recursion failed (no delegation record 
found)\n"));
   fail_resolution (rh);
@@ -2370,6 +2369,7 @@ namecache_cache_continuation (void *cls,
  * @param cls closure with the `struct GNS_ResolverHandle`
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer truncated peer, NULL if not truncated
  * @param get_path peers on reply path (or NULL if not recorded)
  *                 [0] = datastore's first neighbor, [length - 1] = local peer
  * @param get_path_length number of entries in @a get_path
@@ -2384,6 +2384,7 @@ static void
 handle_dht_response (void *cls,
                      struct GNUNET_TIME_Absolute exp,
                      const struct GNUNET_HashCode *key,
+                     const struct GNUNET_PeerIdentity *trunc_peer,
                      const struct GNUNET_DHT_PathElement *get_path,
                      unsigned int get_path_length,
                      const struct GNUNET_DHT_PathElement *put_path,
@@ -2552,7 +2553,8 @@ handle_namecache_block_response (void *cls,
   else
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Got block with expiration %s\n",
-                GNUNET_STRINGS_absolute_time_to_string 
(GNUNET_GNSRECORD_block_get_expiration (block)));
+                GNUNET_STRINGS_absolute_time_to_string (
+                  GNUNET_GNSRECORD_block_get_expiration (block)));
   if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
        ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
         (ac != rh->ac_head))) &&
diff --git a/src/include/gnunet_datacache_lib.h 
b/src/include/gnunet_datacache_lib.h
index c4d74524a..b4ef346e2 100644
--- a/src/include/gnunet_datacache_lib.h
+++ b/src/include/gnunet_datacache_lib.h
@@ -65,6 +65,12 @@ struct GNUNET_DATACACHE_Block
    */
   struct GNUNET_TIME_Absolute expiration_time;
 
+  /**
+   * If the path was truncated, this is the peer
+   * ID at which the path was truncated.
+   */
+  struct GNUNET_PeerIdentity trunc_peer;
+
   /**
    * PUT path taken by the block, array of peer identities.
    */
diff --git a/src/include/gnunet_dht_service.h b/src/include/gnunet_dht_service.h
index d683ae0bf..49a7831e6 100644
--- a/src/include/gnunet_dht_service.h
+++ b/src/include/gnunet_dht_service.h
@@ -268,6 +268,7 @@ GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph);
  * @param cls closure
  * @param exp when will this value expire
  * @param query_hash key of the query
+ * @param trunc_peer peer where the path was truncated, or NULL if the path is 
complete
  * @param get_path peers on reply path (or NULL if not recorded)
  *                 [0] = datastore's first neighbor, [length - 1] = local peer
  * @param get_path_length number of entries in @a get_path
@@ -284,6 +285,7 @@ typedef void
 (*GNUNET_DHT_GetIterator) (void *cls,
                            struct GNUNET_TIME_Absolute exp,
                            const struct GNUNET_HashCode *query_hash,
+                           const struct GNUNET_PeerIdentity *trunc_peer,
                            const struct GNUNET_DHT_PathElement *get_path,
                            unsigned int get_path_length,
                            const struct GNUNET_DHT_PathElement *put_path,
@@ -359,10 +361,6 @@ struct GNUNET_DHT_MonitorHandle;
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
- * @param path_length number of entries in @a path (or 0 if not recorded).
- * @param path peers on the GET path (or NULL if not recorded).
- *        note that the last signature will be all zeros as
- *        we did not forward and thus did not sign!
  * @param desired_replication_level Desired replication level.
  * @param key Key of the requested data.
  */
@@ -372,8 +370,6 @@ typedef void
                             enum GNUNET_BLOCK_Type type,
                             uint32_t hop_count,
                             uint32_t desired_replication_level,
-                            unsigned int path_length,
-                            const struct GNUNET_DHT_PathElement *path,
                             const struct GNUNET_HashCode *key);
 
 
@@ -382,6 +378,7 @@ typedef void
  *
  * @param cls Closure.
  * @param type The type of data in the result.
+ * @param trunc_peer peer where the path was truncated, or NULL if the path is 
complete
  * @param get_path Peers on GET path (or NULL if not recorded).
  *        note that the last signature will be all zeros as
  *        we did not forward and thus did not sign!
@@ -396,6 +393,7 @@ typedef void
 typedef void
 (*GNUNET_DHT_MonitorGetRespCB) (void *cls,
                                 enum GNUNET_BLOCK_Type type,
+                                const struct GNUNET_PeerIdentity *trunc_peer,
                                 const struct GNUNET_DHT_PathElement *get_path,
                                 unsigned int get_path_length,
                                 const struct GNUNET_DHT_PathElement *put_path,
@@ -413,11 +411,12 @@ typedef void
  * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
  * @param type The type of data in the request.
  * @param hop_count Hop count so far.
+ * @param desired_replication_level Desired replication level.
+ * @param trunc_peer peer where the path was truncated, or NULL if the path is 
complete
  * @param path_length number of entries in @a path (or 0 if not recorded).
  * @param path peers on the PUT path (or NULL if not recorded).
  *        note that the last signature will be all zeros as
  *        we did not forward and thus did not sign!
- * @param desired_replication_level Desired replication level.
  * @param exp Expiration time of the data.
  * @param key Key under which data is to be stored.
  * @param data Pointer to the data carried.
@@ -429,6 +428,7 @@ typedef void
                             enum GNUNET_BLOCK_Type type,
                             uint32_t hop_count,
                             uint32_t desired_replication_level,
+                            const struct GNUNET_PeerIdentity *trunc_peer,
                             unsigned int path_length,
                             const struct GNUNET_DHT_PathElement *path,
                             struct GNUNET_TIME_Absolute exp,
@@ -491,6 +491,8 @@ GNUNET_DHT_pp2s (const struct GNUNET_DHT_PathElement *path,
  * @param data payload (the block)
  * @param data_size number of bytes in @a data
  * @param exp_time expiration time of @a data
+ * @param trunc_peer peer which signature was broken or where the path was 
truncated,
+ *                  NULL if path is not truncated
  * @param get_path array of path elements to verify
  * @param get_path_len length of the @a get_path array
  * @param put_path array of path elements to verify
@@ -498,12 +500,13 @@ GNUNET_DHT_pp2s (const struct GNUNET_DHT_PathElement 
*path,
  * @param me our own peer identity (needed to verify the last element)
  * @return 0 on success, otherwise the index of
  *         the last path element that succeeded with verification;
- *         @a get_path_len + @a put_path_len - 1 if no signature was valid
+ *         @a get_path_len + @a put_path_len if no signature was valid
  */
 unsigned int
 GNUNET_DHT_verify_path (const void *data,
                         size_t data_size,
                         struct GNUNET_TIME_Absolute exp_time,
+                        const struct GNUNET_PeerIdentity *trunc_peer,
                         const struct GNUNET_DHT_PathElement *put_path,
                         unsigned int put_path_len,
                         const struct GNUNET_DHT_PathElement *get_path,
diff --git a/src/pt/gnunet-daemon-pt.c b/src/pt/gnunet-daemon-pt.c
index b79a8e464..67227b97f 100644
--- a/src/pt/gnunet-daemon-pt.c
+++ b/src/pt/gnunet-daemon-pt.c
@@ -1126,6 +1126,7 @@ try_open_exit ()
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer peer that was truncated (or NULL if not truncated)
  * @param get_path peers on reply path (or NULL if not recorded)
  *                 [0] = datastore's first neighbor, [length - 1] = local peer
  * @param get_path_length number of entries in @a get_path
@@ -1140,6 +1141,7 @@ static void
 handle_dht_result (void *cls,
                    struct GNUNET_TIME_Absolute exp,
                    const struct GNUNET_HashCode *key,
+                   const struct GNUNET_PeerIdentity *trunc_peer,
                    const struct GNUNET_DHT_PathElement *get_path,
                    unsigned int get_path_length,
                    const struct GNUNET_DHT_PathElement *put_path,
diff --git a/src/regex/regex_internal_dht.c b/src/regex/regex_internal_dht.c
index 2248de1f1..e578fba2c 100644
--- a/src/regex/regex_internal_dht.c
+++ b/src/regex/regex_internal_dht.c
@@ -372,6 +372,7 @@ regex_next_edge (const struct RegexBlock *block,
  *
  * @param cls Closure (search context).
  * @param exp When will this value expire.
+ * @param trunc_peer truncated peer, or NULL if none was truncated
  * @param key Key of the result.
  * @param get_path Path of the get request.
  * @param get_path_length Length of get_path.
@@ -384,6 +385,7 @@ regex_next_edge (const struct RegexBlock *block,
 static void
 dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                                const struct GNUNET_HashCode *key,
+                               const struct GNUNET_PeerIdentity *trunc_peer,
                                const struct GNUNET_DHT_PathElement *get_path,
                                unsigned int get_path_length,
                                const struct GNUNET_DHT_PathElement *put_path,
@@ -451,6 +453,7 @@ regex_find_path (const struct GNUNET_HashCode *key,
  * @param cls closure (search context)
  * @param exp when will this value expire
  * @param key key of the result
+ * @param trunc_peer NULL if not truncated
  * @param get_path path of the get request (not used)
  * @param get_path_length length of @a get_path (not used)
  * @param put_path path of the put request (not used)
@@ -464,6 +467,7 @@ regex_find_path (const struct GNUNET_HashCode *key,
 static void
 dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                         const struct GNUNET_HashCode *key,
+                        const struct GNUNET_PeerIdentity *trunc_peer,
                         const struct GNUNET_DHT_PathElement *get_path,
                         unsigned int get_path_length,
                         const struct GNUNET_DHT_PathElement *put_path,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]