GNUnet 0.27.0
 
Loading...
Searching...
No Matches
dht_helper.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2024, 2026 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
26#include "gnunet-service-dht.h"
27#include "gnunet_constants.h"
28#include "gnunet_common.h"
29#include "gnunet_signatures.h"
30#include "gnunet_dht_service.h"
31#include "gnunet_pils_service.h"
32#include "gnunet_time_lib.h"
33#include "gnunet_util_lib.h"
34#include "dht.h"
35#include "dht_helper.h"
36
37
49
52
65
66
67static void
69{
71 if (op->sign_op)
72 GNUNET_PILS_cancel (op->sign_op);
73 if ((free_data) && (op->cb_data) && (op->heap))
74 GNUNET_free (op->cb_data);
77}
78
79
80void
82{
83 struct GDS_HelperOperation *op;
84 while (op_head)
85 {
86 bool free_data = true;
87 op = op_head;
88 if (op->cb)
89 free_data = op->cb (op->cb_data, NULL);
90 cleanup_helper_operation (op, free_data);
91 }
92}
93
94
97 const struct GNUNET_PeerIdentity *my_identity,
98 enum GNUNET_DHT_RouteOption ro_in,
99 enum GNUNET_DHT_RouteOption *ro_out,
101 block_expiration_time,
102 const uint8_t *block_data,
103 size_t block_data_len,
104 const struct GNUNET_DHT_PathElement *
105 put_path_in,
106 unsigned int put_path_len_in,
107 unsigned int *put_path_len_out,
108 const struct GNUNET_PeerIdentity *trunc_peer,
109 struct GNUNET_PeerIdentity *trunc_peer_out,
110 bool *truncated)
111{
112 size_t msize;
113 const struct GNUNET_DHT_PathElement *put_path_out = put_path_in;
114 bool tracking = (0 != (ro_in & GNUNET_DHT_RO_RECORD_ROUTE));
115 *truncated = (0 != (ro_in & GNUNET_DHT_RO_TRUNCATED));
116 *put_path_len_out = put_path_len_in;
117 *ro_out = ro_in;
118 if (NULL != trunc_peer)
119 {
120 *trunc_peer_out = *trunc_peer;
121 }
122
123#if SANITY_CHECKS > 1
124 unsigned int failure_offset;
125
126 failure_offset
127 = GNUNET_DHT_verify_path (block_data,
128 block_data_len,
129 block_expiration_time,
130 trunc_peer,
131 put_path_in,
132 put_path_len_in, bb
133 NULL, 0, /* get_path */
135 if (0 != failure_offset)
136 {
137 GNUNET_break_op (0);
138 truncated = true;
139 *trunc_peer_out = put_path_out[failure_offset - 1].pred;
140 put_path_out = &put_path_out[failure_offset];
141 *put_path_len_out = put_path_len_in - failure_offset;
142 *ro_out |= GNUNET_DHT_RO_TRUNCATED;
143 }
144#endif
145
146 if (block_data_len
148 - sizeof(struct PeerPutMessage))
149 {
150 GNUNET_break (0);
151 *msize_out = 0;
152 return GNUNET_SYSERR;
153 }
154 msize = block_data_len + sizeof(struct PeerPutMessage);
155 if (tracking)
156 {
157 if (msize + sizeof (struct GNUNET_CRYPTO_EddsaSignature)
159 {
161 "Discarding message that is too large due to tracking\n");
162 *msize_out = 0;
163 return GNUNET_NO;
164 }
165 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
166 }
167 else
168 {
169 /* If tracking is disabled, also discard any path we might have
170 gotten from some broken peer */
171 GNUNET_break_op (0 == *put_path_len_out);
172 *put_path_len_out = 0;
173 }
174 if (*truncated)
175 msize += sizeof (struct GNUNET_PeerIdentity);
176 if (msize + *put_path_len_out * sizeof(struct GNUNET_DHT_PathElement)
178 {
179 unsigned int mlen;
180 unsigned int ppl;
181
183 "Truncating path that is too large due\n");
185 if (! *truncated)
186 {
187 /* We need extra space for the truncation, consider that,
188 too! */
189 *truncated = true;
190 mlen -= sizeof (struct GNUNET_PeerIdentity);
191 msize += sizeof (struct GNUNET_PeerIdentity);
192 }
193 /* compute maximum length of path we can keep */
194 ppl = mlen / sizeof (struct GNUNET_DHT_PathElement);
195 GNUNET_assert (*put_path_len_out - ppl > 0);
196 *trunc_peer_out = put_path_out[*put_path_len_out - ppl - 1].pred;
197 put_path_out = &put_path_out[*put_path_len_out - ppl];
198 *put_path_len_out = ppl;
199 *ro_out |= GNUNET_DHT_RO_TRUNCATED;
200 }
201 else
202 {
203 msize += put_path_len_in * sizeof(struct GNUNET_DHT_PathElement);
204 }
205 *msize_out = msize;
206 return GNUNET_OK;
207}
208
209
210static void
211cb_sign_result (void *cls,
212 const struct GNUNET_PeerIdentity *pid,
213 const struct GNUNET_CRYPTO_EddsaSignature *sig)
214{
215 struct GDS_HelperOperation *op = cls;
216 bool free_data;
217 if (op->cb)
218 free_data = op->cb (op->cb_data, sig);
219 else
220 free_data = true;
221 cleanup_helper_operation (op, free_data);
222}
223
224
225bool
227 size_t data_size,
228 const struct GNUNET_CRYPTO_EddsaPrivateKey *sk,
229 struct GNUNET_TIME_Absolute exp_time,
230 const struct GNUNET_PeerIdentity *pred,
231 const struct GNUNET_PeerIdentity *succ,
233 size_t cb_data_size,
234 void *cb_data)
235{
236 struct GNUNET_DHT_HopSignature hs = {
238 .purpose.size = htonl (sizeof (hs)),
239 .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
240 .succ = *succ
241 };
242
243 if (NULL != pred)
244 hs.pred = *pred;
246 data_size,
247 &hs.h_data);
248
249 if (sk)
250 {
253 &hs,
254 &sig);
255 if (cb)
256 return cb (cb_data, &sig);
257 else
258 return true;
259 }
260 else
261 {
262 struct GDS_HelperOperation *op;
264 op->cb = cb;
265 if (cb_data_size > 0)
266 {
267 op->cb_data = GNUNET_memdup (cb_data, cb_data_size);
268 op->heap = true;
269 }
270 else
271 {
272 op->cb_data = cb_data;
273 op->heap = false;
274 }
277 &hs.purpose,
279 op);
280 if (NULL == op->sign_op)
281 {
283 return true;
284 }
285 else
286 return (cb_data_size > 0);
287 }
288}
289
290
291static bool
292cb_path_signed (void *cls,
293 const struct GNUNET_CRYPTO_EddsaSignature *sig)
294{
295 struct GDS_HelperMsgData *msg_data = cls;
296 bool free_data;
297
298 if (sig)
299 {
300 unsigned int put_path_len;
301 put_path_len = ntohs (msg_data->ppm->put_path_length);
303 "Signing PUT PATH %u => %s\n",
304 put_path_len,
305 GNUNET_B2S (sig));
306 memcpy (msg_data->sig, sig, sizeof (*sig));
307 }
308
309 if (msg_data->cb)
310 free_data = msg_data->cb (msg_data->cb_data,
311 msg_data->msize,
312 sig? msg_data->ppm : NULL);
313 else
314 free_data = true;
315
316 if ((free_data) && (msg_data->cb_data) && (msg_data->heap))
317 GNUNET_free (msg_data->cb_data);
318 if (msg_data->heap_msg)
319 GNUNET_free (msg_data->ppm);
320
321 return true;
322}
323
324
325bool
327 size_t msize,
328 const struct GNUNET_CRYPTO_EddsaPrivateKey *sk,
329 const struct GNUNET_PeerIdentity *target,
330 const struct GNUNET_HashCode *target_hash,
331 const struct GNUNET_CONTAINER_BloomFilter *bf,
332 const struct GNUNET_HashCode *block_key,
335 struct GNUNET_TIME_Absolute block_expiration_time,
336 const uint8_t *block_data,
337 size_t block_data_len,
338 const struct GNUNET_DHT_PathElement *put_path,
339 unsigned int put_path_len,
340 size_t hop_count,
341 uint32_t desired_replication_level,
342 const struct GNUNET_PeerIdentity *trunc_peer,
344 size_t cb_data_size,
345 void *cb_data)
346{
347 struct GNUNET_DHT_PathElement *pp;
348 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
349 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
350 void *data;
351
353 ppm->header.size = htons (msize);
354 ppm->type = htonl (block_type);
355 ppm->options = htons (ro);
356 ppm->hop_count = htons (hop_count + 1);
357 ppm->desired_replication_level = htons (desired_replication_level);
358 ppm->put_path_length = htons (put_path_len);
359 ppm->expiration_time = GNUNET_TIME_absolute_hton (block_expiration_time);
362 target_hash));
365 ppm->bloomfilter,
367 ppm->key = *block_key;
368 if (truncated)
369 {
370 void *tgt = &ppm[1];
371
372 GNUNET_memcpy (tgt,
373 trunc_peer,
374 sizeof (struct GNUNET_PeerIdentity));
375 pp = (struct GNUNET_DHT_PathElement *)
376 (tgt + sizeof (struct GNUNET_PeerIdentity));
377 }
378 else
379 {
380 pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
381 }
382 GNUNET_memcpy (pp,
383 put_path,
384 sizeof (struct GNUNET_DHT_PathElement) * put_path_len);
385 if (tracking)
386 {
387 void *tgt = &pp[put_path_len];
388 data = tgt + sizeof (struct GNUNET_CRYPTO_EddsaSignature);
389 }
390 else
391 {
392 data = &ppm[1];
393 }
394
396 block_data,
397 block_data_len);
398 if (tracking)
399 {
400 const struct GNUNET_PeerIdentity *pred;
401 void *tgt = &pp[put_path_len];
402
403 if (0 == put_path_len)
404 {
405 /* Note that the signature in 'put_path' was not initialized before,
406 so this is crucial to avoid sending garbage. */
407 pred = trunc_peer;
408 }
409 else
410 pred = &pp[put_path_len - 1].pred;
411
412 if (sk)
413 {
414 struct GDS_HelperMsgData msg_data;
415 msg_data.ppm = ppm;
416 msg_data.msize = msize;
417 msg_data.sig = tgt;
418 msg_data.heap_msg = false;
419 msg_data.cb = cb;
420 msg_data.cb_data = cb_data;
421 msg_data.heap = false;
422
423 return GDS_helper_sign_path (block_data,
424 block_data_len,
425 sk,
426 block_expiration_time,
427 pred,
428 target,
430 sizeof (msg_data),
431 &msg_data) && (cb_data_size > 0);
432 }
433 else
434 {
435 struct GDS_HelperMsgData msg_data;
436 msg_data.ppm = GNUNET_memdup (ppm, msize);
437 msg_data.msize = msize;
438 msg_data.sig = (struct GNUNET_CRYPTO_EddsaSignature*) (
439 ((size_t) msg_data.ppm) + ((size_t) tgt) - ((size_t) ppm));
440 msg_data.heap_msg = true;
441 msg_data.cb = cb;
442
443 if (cb_data_size > 0)
444 {
445 msg_data.cb_data = GNUNET_memdup (cb_data, cb_data_size);
446 msg_data.heap = true;
447 }
448 else
449 {
450 msg_data.cb_data = cb_data;
451 msg_data.heap = false;
452 }
453
454 return GDS_helper_sign_path (block_data,
455 block_data_len,
456 sk,
457 block_expiration_time,
458 pred,
459 target,
461 sizeof (msg_data),
462 &msg_data) && (cb_data_size > 0);
463 }
464 }
465 else if (cb)
466 return cb (cb_data, msize, ppm);
467 else
468 return true;
469}
#define DHT_BLOOM_SIZE
Size of the bloom filter the DHT uses to filter peers.
Definition dht.h:34
bool GDS_helper_make_put_message(struct PeerPutMessage *ppm, size_t msize, const struct GNUNET_CRYPTO_EddsaPrivateKey *sk, const struct GNUNET_PeerIdentity *target, const struct GNUNET_HashCode *target_hash, const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *block_key, enum GNUNET_DHT_RouteOption ro, enum GNUNET_BLOCK_Type block_type, struct GNUNET_TIME_Absolute block_expiration_time, const uint8_t *block_data, size_t block_data_len, const struct GNUNET_DHT_PathElement *put_path, unsigned int put_path_len, size_t hop_count, uint32_t desired_replication_level, const struct GNUNET_PeerIdentity *trunc_peer, GDS_HelperMsgCallback cb, size_t cb_data_size, void *cb_data)
Definition dht_helper.c:326
static void cleanup_helper_operation(struct GDS_HelperOperation *op, bool free_data)
Definition dht_helper.c:68
bool GDS_helper_sign_path(const void *data, size_t data_size, const struct GNUNET_CRYPTO_EddsaPrivateKey *sk, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *pred, const struct GNUNET_PeerIdentity *succ, GDS_HelperCallback cb, size_t cb_data_size, void *cb_data)
Sign that we are routing a message from pred to succ.
Definition dht_helper.c:226
static struct GDS_HelperOperation * op_head
Definition dht_helper.c:50
enum GNUNET_GenericReturnValue GDS_helper_put_message_get_size(size_t *msize_out, const struct GNUNET_PeerIdentity *my_identity, enum GNUNET_DHT_RouteOption ro_in, enum GNUNET_DHT_RouteOption *ro_out, struct GNUNET_TIME_Absolute block_expiration_time, const uint8_t *block_data, size_t block_data_len, const struct GNUNET_DHT_PathElement *put_path_in, unsigned int put_path_len_in, unsigned int *put_path_len_out, const struct GNUNET_PeerIdentity *trunc_peer, struct GNUNET_PeerIdentity *trunc_peer_out, bool *truncated)
Definition dht_helper.c:96
static bool cb_path_signed(void *cls, const struct GNUNET_CRYPTO_EddsaSignature *sig)
Definition dht_helper.c:292
static struct GDS_HelperOperation * op_tail
Definition dht_helper.c:51
void GDS_helper_cleanup_operations(void)
Definition dht_helper.c:81
static void cb_sign_result(void *cls, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
Definition dht_helper.c:211
Helper functions for DHT.
struct GNUNET_PILS_Handle * GDS_pils
Handle for the pils service.
bool(* GDS_HelperMsgCallback)(void *cls, size_t msize, struct PeerPutMessage *ppm)
Definition dht_helper.h:47
bool(* GDS_HelperCallback)(void *cls, const struct GNUNET_CRYPTO_EddsaSignature *sig)
Definition dht_helper.h:43
static struct GNUNET_ARM_Operation * op
Current operation.
Definition gnunet-arm.c:143
static unsigned int block_type
The type of the query.
static char * data
The data to insert into the dht.
static size_t data_size
Number of bytes in data.
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
GNUnet DHT globals.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
API to the DHT service.
void GNUNET_PILS_cancel(struct GNUNET_PILS_Operation *op)
Cancel request.
Definition pils_api.c:623
struct GNUNET_PILS_Operation * GNUNET_PILS_sign_by_peer_identity(struct GNUNET_PILS_Handle *handle, const struct GNUNET_CRYPTO_SignaturePurpose *purpose, GNUNET_PILS_SignResultCallback cb, void *cb_cls)
Sign data with the peer id.
Definition pils_api.c:528
#define GNUNET_SIGNATURE_PURPOSE_DHT_HOP
Signature by which a peer affirms that it forwarded a message in the DHT.
Functions related to time.
bool GNUNET_CONTAINER_bloomfilter_test(const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Test if an element is in the filter.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_bloomfilter_get_raw_data(const struct GNUNET_CONTAINER_BloomFilter *bf, char *data, size_t size)
Copy the raw data of this Bloom filter into the given data array.
#define GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
What is the maximum size for encrypted messages? Note that this number imposes a clear limit on the m...
#define GNUNET_CRYPTO_eddsa_sign(priv, ps, sig)
EdDSA sign a given block.
GNUNET_DHT_RouteOption
Options for routing.
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, unsigned int get_path_len, const struct GNUNET_PeerIdentity *me)
Verify signatures on a path consisting of put_path and get_path in reverse order (starting at the las...
Definition dht_api.c:1355
@ GNUNET_DHT_RO_TRUNCATED
Flag set if the path was truncated.
@ GNUNET_DHT_RO_RECORD_ROUTE
We should keep track of the route that the message took in the P2P network.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:41
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
Peer is storing data in DHT.
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
GDS_HelperMsgCallback cb
Definition dht_helper.c:61
struct GNUNET_CRYPTO_EddsaSignature * sig
Definition dht_helper.c:58
struct PeerPutMessage * ppm
Definition dht_helper.c:55
struct GDS_HelperOperation * next
Definition dht_helper.c:41
struct GNUNET_PILS_Operation * sign_op
Definition dht_helper.c:43
GDS_HelperCallback cb
Definition dht_helper.c:45
struct GDS_HelperOperation * prev
Definition dht_helper.c:40
Private ECC key encoded for transmission.
an ECC signature using EdDSA.
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
Message signed by a peer when doing path tracking.
struct GNUNET_CRYPTO_SignaturePurpose purpose
Must be GNUNET_SIGNATURE_PURPOSE_DHT_HOP.
struct GNUNET_HashCode h_data
Hash over the payload of the block.
struct GNUNET_PeerIdentity pred
Previous hop the message was received from.
struct GNUNET_PeerIdentity succ
Next hop the message was forwarded to.
A (signed) path tracking a block's flow through the DHT is represented by an array of path elements,...
struct GNUNET_PeerIdentity pred
Previous peer on the path (matches "pred" in the signed field).
struct GNUNET_CRYPTO_EddsaSignature sig
Signature affirming the hop of type GNUNET_SIGNATURE_PURPOSE_DHT_HOP.
A 512-bit hashcode.
The identity of the host (wraps the signing key of the peer).
Time for absolute times used by GNUnet, in microseconds.
P2P PUT message.
Definition dht.h:429
uint16_t desired_replication_level
Replication level for this message.
Definition dht.h:453
uint16_t hop_count
Hop count.
Definition dht.h:448
uint32_t type
Content type, must not be zero.
Definition dht.h:438
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
Definition dht.h:468
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT.
Definition dht.h:433
struct GNUNET_HashCode key
The key we are storing under.
Definition dht.h:473
uint16_t options
Processing options.
Definition dht.h:443
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
Definition dht.h:463
uint16_t put_path_length
Length of the PUT path that follows (if tracked).
Definition dht.h:458