aboutsummaryrefslogtreecommitdiff
path: root/src/lib/hello/hello-uri.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hello/hello-uri.c')
-rw-r--r--src/lib/hello/hello-uri.c964
1 files changed, 964 insertions, 0 deletions
diff --git a/src/lib/hello/hello-uri.c b/src/lib/hello/hello-uri.c
new file mode 100644
index 000000000..25f8948fe
--- /dev/null
+++ b/src/lib/hello/hello-uri.c
@@ -0,0 +1,964 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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
21/**
22 * @file hello/hello-uri.c
23 * @brief helper library for handling URI-based HELLOs
24 * @author Christian Grothoff
25 *
26 * Note:
27 * - Current API does not support deserializing HELLO of
28 * another peer and then serializing it into another
29 * format (we always require the private key).
30 * Not sure if we need this, but if we do, we need
31 * to extend the builder and the API.
32 * - Current API does not allow overriding the default
33 * HELLO expiration time. We may want to add a function
34 * that does this to create bootstrap HELLOs shipped with
35 * the TGZ.
36 */
37#include "platform.h"
38#include "gnunet_signatures.h"
39#include "gnunet_hello_uri_lib.h"
40#include "gnunet_protocols.h"
41#include "gnunet_util_lib.h"
42
43
44GNUNET_NETWORK_STRUCT_BEGIN
45
46/**
47 * Message signed as part of a HELLO block/URL.
48 */
49struct HelloSignaturePurpose
50{
51 /**
52 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_HELLO
53 */
54 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
55
56 /**
57 * When does the signature expire?
58 */
59 struct GNUNET_TIME_AbsoluteNBO expiration_time;
60
61 /**
62 * Hash over all addresses.
63 */
64 struct GNUNET_HashCode h_addrs;
65
66};
67
68/**
69 * Message used when gossiping HELLOs between peers.
70 */
71struct HelloUriMessage
72{
73 /**
74 * Type must be #GNUNET_MESSAGE_TYPE_HELLO_URI
75 */
76 struct GNUNET_MessageHeader header;
77
78 /**
79 * Reserved. 0.
80 */
81 uint16_t reserved GNUNET_PACKED;
82
83 /**
84 * Number of URLs encoded after the end of the struct, in NBO.
85 */
86 uint16_t url_counter GNUNET_PACKED;
87
88 /* followed by a 'block' */
89};
90
91
92/**
93 * Start of a 'block'.
94 */
95struct BlockHeader
96{
97 /**
98 * Public key of the peer.
99 */
100 struct GNUNET_PeerIdentity pid;
101
102 /**
103 * Signature over the block, of purpose #GNUNET_SIGNATURE_PURPOSE_HELLO.
104 */
105 struct GNUNET_CRYPTO_EddsaSignature sig;
106
107 /**
108 * When does the HELLO expire?
109 */
110 struct GNUNET_TIME_AbsoluteNBO expiration_time;
111
112};
113
114
115/**
116 * Message used when a DHT provides its HELLO to direct
117 * neighbours.
118 */
119struct DhtHelloMessage
120{
121 /**
122 * Type must be #GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO
123 */
124 struct GNUNET_MessageHeader header;
125
126 /**
127 * Reserved. 0.
128 */
129 uint16_t reserved GNUNET_PACKED;
130
131 /**
132 * Number of URLs encoded after the end of the struct, in NBO.
133 */
134 uint16_t url_counter GNUNET_PACKED;
135
136 /**
137 * Signature over the block, of purpose #GNUNET_SIGNATURE_PURPOSE_HELLO.
138 */
139 struct GNUNET_CRYPTO_EddsaSignature sig;
140
141 /**
142 * When does the HELLO expire?
143 */
144 struct GNUNET_TIME_AbsoluteNBO expiration_time;
145
146 /* followed by the serialized addresses of the 'block' */
147};
148
149
150GNUNET_NETWORK_STRUCT_END
151
152
153/**
154 * Address of a peer.
155 */
156struct Address
157{
158 /**
159 * Kept in a DLL.
160 */
161 struct Address *next;
162
163 /**
164 * Kept in a DLL.
165 */
166 struct Address *prev;
167
168 /**
169 * Actual URI, allocated at the end of this struct.
170 */
171 const char *uri;
172
173 /**
174 * Length of @a uri including 0-terminator.
175 */
176 size_t uri_len;
177};
178
179
180/**
181 * Context for building (or parsing) HELLO URIs.
182 */
183struct GNUNET_HELLO_Builder
184{
185 /**
186 * Public key of the peer.
187 */
188 struct GNUNET_PeerIdentity pid;
189
190 /**
191 * Head of the addresses DLL.
192 */
193 struct Address *a_head;
194
195 /**
196 * Tail of the addresses DLL.
197 */
198 struct Address *a_tail;
199
200 /**
201 * Length of the @a a_head DLL.
202 */
203 unsigned int a_length;
204
205};
206
207/**
208 * Struct to wrap data to do the merge of to hello uris.
209 */
210struct AddressUriMergeResult
211{
212 /**
213 * The builder of the hello uri we merge with.
214 */
215 struct GNUNET_HELLO_Builder *builder;
216
217 /**
218 * The actual address to check, if it is allready in the hello uri we merge with.
219 */
220 const char *address_uri;
221
222 /**
223 * Did we found the actual address to check.
224 */
225 unsigned int found;
226
227 /**
228 * Did we found at least one address to merge.
229 */
230 unsigned int merged;
231};
232
233
234/**
235 * Compute @a hash over addresses in @a builder.
236 *
237 * @param builder the builder to hash addresses of
238 * @param[out] hash where to write the hash
239 */
240static void
241hash_addresses (const struct GNUNET_HELLO_Builder *builder,
242 struct GNUNET_HashCode *hash)
243{
244 struct GNUNET_HashContext *hc;
245
246 hc = GNUNET_CRYPTO_hash_context_start ();
247 for (struct Address *a = builder->a_head;
248 NULL != a;
249 a = a->next)
250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252 "Hashing over %.*s\n",
253 (int) a->uri_len,
254 a->uri);
255 GNUNET_CRYPTO_hash_context_read (hc,
256 a->uri,
257 a->uri_len);
258 }
259 GNUNET_CRYPTO_hash_context_finish (hc,
260 hash);
261
262}
263
264
265/**
266 * Create HELLO signature.
267 *
268 * @param builder the builder to use
269 * @param et expiration time to sign
270 * @param priv key to sign with
271 * @param[out] sig where to write the signature
272 */
273static void
274sign_hello (const struct GNUNET_HELLO_Builder *builder,
275 struct GNUNET_TIME_Timestamp et,
276 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
277 struct GNUNET_CRYPTO_EddsaSignature *sig)
278{
279 struct HelloSignaturePurpose hsp = {
280 .purpose.size = htonl (sizeof (hsp)),
281 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
282 .expiration_time = GNUNET_TIME_absolute_hton (et.abs_time)
283 };
284
285 hash_addresses (builder,
286 &hsp.h_addrs);
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Address hash is %s\n",
289 GNUNET_h2s_full (&hsp.h_addrs));
290 GNUNET_CRYPTO_eddsa_sign (priv,
291 &hsp,
292 sig);
293}
294
295
296/**
297 * Verify HELLO signature.
298 *
299 * @param builder the builder to use
300 * @param et expiration time to verify
301 * @param sig signature to verify
302 * @return #GNUNET_OK if everything is ok, #GNUNET_NO if the
303 * HELLO expired, #GNUNET_SYSERR if the signature is wrong
304 */
305static enum GNUNET_GenericReturnValue
306verify_hello (const struct GNUNET_HELLO_Builder *builder,
307 struct GNUNET_TIME_Absolute et,
308 const struct GNUNET_CRYPTO_EddsaSignature *sig)
309{
310 struct HelloSignaturePurpose hsp = {
311 .purpose.size = htonl (sizeof (hsp)),
312 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
313 .expiration_time = GNUNET_TIME_absolute_hton (et)
314 };
315
316 hash_addresses (builder,
317 &hsp.h_addrs);
318 if (GNUNET_OK !=
319 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_HELLO,
320 &hsp,
321 sig,
322 &builder->pid.public_key))
323 {
324 GNUNET_break_op (0);
325 return GNUNET_SYSERR;
326 }
327 if (GNUNET_TIME_absolute_is_past (et))
328 return GNUNET_NO;
329 return GNUNET_OK;
330}
331
332
333struct GNUNET_HELLO_Builder *
334GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid)
335{
336 struct GNUNET_HELLO_Builder *builder;
337
338 builder = GNUNET_new (struct GNUNET_HELLO_Builder);
339 builder->pid = *pid;
340 return builder;
341}
342
343
344const struct GNUNET_PeerIdentity *
345GNUNET_HELLO_builder_get_id (const struct GNUNET_HELLO_Builder *builder)
346{
347 return &builder->pid;
348}
349
350
351void
352GNUNET_HELLO_builder_free (struct GNUNET_HELLO_Builder *builder)
353{
354 struct Address *a;
355
356 while (NULL != (a = builder->a_head))
357 {
358 GNUNET_CONTAINER_DLL_remove (builder->a_head,
359 builder->a_tail,
360 a);
361 builder->a_length--;
362 GNUNET_free (a);
363 }
364 GNUNET_assert (0 == builder->a_length);
365 GNUNET_free (builder);
366}
367
368
369struct GNUNET_HELLO_Builder *
370GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg)
371{
372 const struct HelloUriMessage *h;
373 uint16_t size = ntohs (msg->size);
374
375 if (GNUNET_MESSAGE_TYPE_HELLO_URI != ntohs (msg->type))
376 {
377 GNUNET_break (0);
378 return NULL;
379 }
380 if (sizeof (struct HelloUriMessage) > size)
381 {
382 GNUNET_break_op (0);
383 return NULL;
384 }
385 h = (const struct HelloUriMessage *) msg;
386 size -= sizeof (*h);
387 return GNUNET_HELLO_builder_from_block (&h[1],
388 size);
389}
390
391
392struct GNUNET_HELLO_Builder *
393GNUNET_HELLO_builder_from_block (const void *block,
394 size_t block_size)
395{
396 const struct BlockHeader *bh = block;
397 struct GNUNET_HELLO_Builder *b;
398
399 if (block_size < sizeof (*bh))
400 {
401 GNUNET_break_op (0);
402 return NULL;
403 }
404 b = GNUNET_HELLO_builder_new (&bh->pid);
405 block += sizeof (*bh);
406 block_size -= sizeof (*bh);
407 while (block_size > 0)
408 {
409 const void *end = memchr (block,
410 '\0',
411 block_size);
412
413 if (NULL == end)
414 {
415 GNUNET_break_op (0);
416 GNUNET_HELLO_builder_free (b);
417 return NULL;
418 }
419 if (GNUNET_OK !=
420 GNUNET_HELLO_builder_add_address (b,
421 block))
422 {
423 GNUNET_break_op (0);
424 GNUNET_HELLO_builder_free (b);
425 return NULL;
426 }
427 end++;
428 block_size -= (end - block);
429 block = end;
430 }
431 {
432 enum GNUNET_GenericReturnValue ret;
433
434 ret = verify_hello (b,
435 GNUNET_TIME_absolute_ntoh (bh->expiration_time),
436 &bh->sig);
437 GNUNET_break (GNUNET_SYSERR != ret);
438 if (GNUNET_OK != ret)
439 {
440 GNUNET_HELLO_builder_free (b);
441 return NULL;
442 }
443 }
444 return b;
445}
446
447
448struct GNUNET_TIME_Absolute
449GNUNET_HELLO_builder_get_expiration_time (const struct
450 GNUNET_MessageHeader *msg)
451{
452 if (GNUNET_MESSAGE_TYPE_HELLO_URI == ntohs (msg->type))
453 {
454 const struct HelloUriMessage *h = (struct HelloUriMessage *) msg;
455 const struct BlockHeader *bh = (const struct BlockHeader *) &h[1];
456
457 return GNUNET_TIME_absolute_ntoh (bh->expiration_time);
458 }
459 else if (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO == ntohs (msg->type))
460 {
461 const struct DhtHelloMessage *dht_hello = (struct DhtHelloMessage *) msg;
462
463 return GNUNET_TIME_absolute_ntoh (dht_hello->expiration_time);
464 }
465 else
466 GNUNET_break (0);
467 return GNUNET_TIME_UNIT_ZERO_ABS;
468}
469
470
471struct GNUNET_HELLO_Builder *
472GNUNET_HELLO_builder_from_url (const char *url)
473{
474 const char *q;
475 const char *s1;
476 const char *s2;
477 struct GNUNET_PeerIdentity pid;
478 struct GNUNET_CRYPTO_EddsaSignature sig;
479 struct GNUNET_TIME_Absolute et;
480 size_t len;
481 struct GNUNET_HELLO_Builder *b;
482
483 if (0 != strncasecmp (url,
484 "gnunet://hello/",
485 strlen ("gnunet://hello/")))
486 return NULL;
487 url += strlen ("gnunet://hello/");
488 s1 = strchr (url, '/');
489 if (NULL == s1)
490 {
491 GNUNET_break_op (0);
492 return NULL;
493 }
494 s2 = strchr (s1 + 1, '/');
495 if (NULL == s1)
496 {
497 GNUNET_break_op (0);
498 return NULL;
499 }
500 q = strchr (url, '?');
501 if (NULL == q)
502 q = url + strlen (url);
503 if (GNUNET_OK !=
504 GNUNET_STRINGS_string_to_data (url,
505 s1 - url,
506 &pid,
507 sizeof(pid)))
508 {
509 GNUNET_break_op (0);
510 return NULL;
511 }
512 if (GNUNET_OK !=
513 GNUNET_STRINGS_string_to_data (s1 + 1,
514 s2 - (s1 + 1),
515 &sig,
516 sizeof(sig)))
517 {
518 GNUNET_break_op (0);
519 return NULL;
520 }
521 {
522 unsigned long long sec;
523 char dummy = '?';
524
525 if ( (0 == sscanf (s2 + 1,
526 "%llu%c",
527 &sec,
528 &dummy)) ||
529 ('?' != dummy) )
530 {
531 GNUNET_break_op (0);
532 return NULL;
533 }
534 et = GNUNET_TIME_absolute_from_s (sec);
535 }
536
537 b = GNUNET_HELLO_builder_new (&pid);
538 len = strlen (q);
539 while (len > 0)
540 {
541 const char *eq;
542 const char *amp;
543 char *addr = NULL;
544 char *uri;
545
546 /* skip ?/& separator */
547 len--;
548 q++;
549 eq = strchr (q, '=');
550 if ( (eq == q) ||
551 (NULL == eq) )
552 {
553 GNUNET_break_op (0);
554 GNUNET_HELLO_builder_free (b);
555 return NULL;
556 }
557 amp = strchr (eq, '&');
558 if (NULL == amp)
559 amp = &q[len];
560 GNUNET_STRINGS_urldecode (eq + 1,
561 amp - (eq + 1),
562 &addr);
563 if ( (NULL == addr) ||
564 (0 == strlen (addr)) )
565 {
566 GNUNET_free (addr);
567 GNUNET_break_op (0);
568 GNUNET_HELLO_builder_free (b);
569 return NULL;
570 }
571 GNUNET_asprintf (&uri,
572 "%.*s://%s",
573 (int) (eq - q),
574 q,
575 addr);
576 GNUNET_free (addr);
577 if (GNUNET_OK !=
578 GNUNET_HELLO_builder_add_address (b,
579 uri))
580 {
581 GNUNET_break_op (0);
582 GNUNET_free (uri);
583 GNUNET_HELLO_builder_free (b);
584 return NULL;
585 }
586 GNUNET_free (uri);
587 /* move to next URL */
588 len -= (amp - q);
589 q = amp;
590 }
591
592 {
593 enum GNUNET_GenericReturnValue ret;
594
595 ret = verify_hello (b,
596 et,
597 &sig);
598 GNUNET_break (GNUNET_SYSERR != ret);
599 if (GNUNET_OK != ret)
600 {
601 GNUNET_HELLO_builder_free (b);
602 return NULL;
603 }
604 }
605 return b;
606}
607
608
609struct GNUNET_MQ_Envelope *
610GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder,
611 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
612 struct GNUNET_TIME_Relative expiration_time)
613{
614 struct GNUNET_MQ_Envelope *env;
615 struct HelloUriMessage *msg;
616 size_t blen;
617
618 if (builder->a_length > UINT16_MAX)
619 {
620 GNUNET_break (0);
621 return NULL;
622 }
623 blen = 0;
624 GNUNET_assert (GNUNET_NO ==
625 GNUNET_HELLO_builder_to_block (builder,
626 priv,
627 NULL,
628 &blen,
629 expiration_time));
630 env = GNUNET_MQ_msg_extra (msg,
631 blen,
632 GNUNET_MESSAGE_TYPE_HELLO_URI);
633 msg->url_counter = htons ((uint16_t) builder->a_length);
634 GNUNET_assert (GNUNET_OK ==
635 GNUNET_HELLO_builder_to_block (builder,
636 priv,
637 &msg[1],
638 &blen,
639 expiration_time));
640 return env;
641}
642
643
644struct GNUNET_MessageHeader *
645GNUNET_HELLO_builder_to_dht_hello_msg (
646 const struct GNUNET_HELLO_Builder *builder,
647 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
648 struct GNUNET_TIME_Relative expiration_time)
649{
650 struct DhtHelloMessage *msg;
651 size_t blen;
652
653 if (builder->a_length > UINT16_MAX)
654 {
655 GNUNET_break (0);
656 return NULL;
657 }
658 blen = 0;
659 GNUNET_assert (GNUNET_NO ==
660 GNUNET_HELLO_builder_to_block (builder,
661 priv,
662 NULL,
663 &blen,
664 expiration_time));
665 GNUNET_assert (blen < UINT16_MAX);
666 GNUNET_assert (blen >= sizeof (struct BlockHeader));
667 {
668 char buf[blen] GNUNET_ALIGN;
669 const struct BlockHeader *block = (const struct BlockHeader *) buf;
670
671 GNUNET_assert (GNUNET_OK ==
672 GNUNET_HELLO_builder_to_block (builder,
673 priv,
674 buf,
675 &blen,
676 expiration_time));
677 msg = GNUNET_malloc (sizeof (*msg)
678 + blen
679 - sizeof (*block));
680 msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO);
681 msg->header.size = htons (sizeof (*msg)
682 + blen
683 - sizeof (*block));
684 memcpy (&msg[1],
685 &block[1],
686 blen - sizeof (*block));
687 msg->sig = block->sig;
688 msg->expiration_time = block->expiration_time;
689 }
690 msg->url_counter = htons ((uint16_t) builder->a_length);
691 return &msg->header;
692}
693
694
695char *
696GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
697 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
698{
699 struct GNUNET_CRYPTO_EddsaSignature sig;
700 struct GNUNET_TIME_Timestamp et;
701 char *result;
702 char *pids;
703 char *sigs;
704 const char *sep = "?";
705
706 et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
707 sign_hello (builder,
708 et,
709 priv,
710 &sig);
711 pids = GNUNET_STRINGS_data_to_string_alloc (&builder->pid,
712 sizeof (builder->pid));
713 sigs = GNUNET_STRINGS_data_to_string_alloc (&sig,
714 sizeof (sig));
715 GNUNET_asprintf (&result,
716 "gnunet://hello/%s/%s/%llu",
717 pids,
718 sigs,
719 (unsigned long long) GNUNET_TIME_timestamp_to_s (et));
720 GNUNET_free (sigs);
721 GNUNET_free (pids);
722 for (struct Address *a = builder->a_head;
723 NULL != a;
724 a = a->next)
725 {
726 char *ue;
727 char *tmp;
728 int pfx_len;
729 const char *eou;
730
731 eou = strstr (a->uri,
732 "://");
733 if (NULL == eou)
734 {
735 GNUNET_break (0);
736 GNUNET_free (result);
737 return NULL;
738 }
739 pfx_len = eou - a->uri;
740 eou += 3;
741 GNUNET_STRINGS_urlencode (eou,
742 a->uri_len - 4 - pfx_len,
743 &ue);
744 GNUNET_asprintf (&tmp,
745 "%s%s%.*s=%s",
746 result,
747 sep,
748 pfx_len,
749 a->uri,
750 ue);
751 GNUNET_free (ue);
752 GNUNET_free (result);
753 result = tmp;
754 sep = "&";
755 }
756 return result;
757}
758
759
760enum GNUNET_GenericReturnValue
761GNUNET_HELLO_builder_to_block (const struct GNUNET_HELLO_Builder *builder,
762 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
763 void *block,
764 size_t *block_size,
765 struct GNUNET_TIME_Relative expiration_time)
766{
767 struct BlockHeader bh;
768 size_t needed = sizeof (bh);
769 char *pos;
770 struct GNUNET_TIME_Timestamp et;
771
772 for (struct Address *a = builder->a_head;
773 NULL != a;
774 a = a->next)
775 {
776 GNUNET_assert (needed + a->uri_len > needed);
777 needed += a->uri_len;
778 }
779 if ( (NULL == block) ||
780 (needed < *block_size) )
781 {
782 *block_size = needed;
783 return GNUNET_NO;
784 }
785 bh.pid = builder->pid;
786 if (GNUNET_TIME_UNIT_ZERO.rel_value_us == expiration_time.rel_value_us)
787 et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
788 else
789 et = GNUNET_TIME_relative_to_timestamp (expiration_time);
790 bh.expiration_time = GNUNET_TIME_absolute_hton (et.abs_time);
791 sign_hello (builder,
792 et,
793 priv,
794 &bh.sig);
795 memcpy (block,
796 &bh,
797 sizeof (bh));
798 pos = block + sizeof (bh);
799 for (struct Address *a = builder->a_head;
800 NULL != a;
801 a = a->next)
802 {
803 memcpy (pos,
804 a->uri,
805 a->uri_len);
806 pos += a->uri_len;
807 }
808 *block_size = needed;
809 return GNUNET_OK;
810}
811
812
813enum GNUNET_GenericReturnValue
814GNUNET_HELLO_builder_add_address (struct GNUNET_HELLO_Builder *builder,
815 const char *address)
816{
817 size_t alen = strlen (address) + 1;
818 struct Address *a;
819 const char *e;
820
821 if (NULL == (e = strstr (address,
822 "://")))
823 {
824 GNUNET_break_op (0);
825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826 "Invalid address `%s'\n",
827 address);
828 return GNUNET_SYSERR;
829 }
830 if (e == address)
831 {
832 GNUNET_break_op (0);
833 return GNUNET_SYSERR;
834 }
835 for (const char *p = address; p != e; p++)
836 if ( (! isalpha ((unsigned char) *p)) &&
837 ('+' != *p) )
838 {
839 GNUNET_break_op (0);
840 return GNUNET_SYSERR;
841 }
842 /* check for duplicates */
843 for (a = builder->a_head;
844 NULL != a;
845 a = a->next)
846 if (0 == strcmp (address,
847 a->uri))
848 return GNUNET_NO;
849 a = GNUNET_malloc (sizeof (struct Address) + alen);
850 a->uri_len = alen;
851 memcpy (&a[1],
852 address,
853 alen);
854 a->uri = (const char *) &a[1];
855 GNUNET_CONTAINER_DLL_insert_tail (builder->a_head,
856 builder->a_tail,
857 a);
858 builder->a_length++;
859 return GNUNET_OK;
860}
861
862
863enum GNUNET_GenericReturnValue
864GNUNET_HELLO_builder_del_address (struct GNUNET_HELLO_Builder *builder,
865 const char *address)
866{
867 struct Address *a;
868
869 /* check for duplicates */
870 for (a = builder->a_head;
871 NULL != a;
872 a = a->next)
873 if (0 == strcmp (address,
874 a->uri))
875 break;
876 if (NULL == a)
877 return GNUNET_NO;
878 GNUNET_CONTAINER_DLL_remove (builder->a_head,
879 builder->a_tail,
880 a);
881 builder->a_length--;
882 GNUNET_free (a);
883 return GNUNET_OK;
884}
885
886
887void
888GNUNET_HELLO_builder_iterate (const struct GNUNET_HELLO_Builder *builder,
889 struct GNUNET_PeerIdentity *pid,
890 GNUNET_HELLO_UriCallback uc,
891 void *uc_cls)
892{
893 struct Address *nxt;
894
895 *pid = builder->pid;
896 if (NULL == uc)
897 return;
898 for (struct Address *a = builder->a_head;
899 NULL != a;
900 a = nxt)
901 {
902 nxt = a->next;
903 uc (uc_cls,
904 a->uri);
905 }
906}
907
908
909enum GNUNET_GenericReturnValue
910GNUNET_HELLO_dht_msg_to_block (const struct GNUNET_MessageHeader *hello,
911 const struct GNUNET_PeerIdentity *pid,
912 void **block,
913 size_t *block_size,
914 struct GNUNET_TIME_Absolute *block_expiration)
915{
916 const struct DhtHelloMessage *msg
917 = (const struct DhtHelloMessage *) hello;
918 uint16_t len = ntohs (hello->size);
919 struct BlockHeader *bh;
920 struct GNUNET_HELLO_Builder *b;
921 enum GNUNET_GenericReturnValue ret;
922
923 if (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO != ntohs (hello->type))
924 {
925 GNUNET_break (0);
926 return GNUNET_SYSERR;
927 }
928 if (len < sizeof (*msg))
929 {
930 GNUNET_break_op (0);
931 return GNUNET_SYSERR;
932 }
933 len -= sizeof (*msg);
934 *block_size = len + sizeof (*bh);
935 *block = GNUNET_malloc (*block_size);
936 bh = *block;
937 bh->pid = *pid;
938 bh->sig = msg->sig;
939 bh->expiration_time = msg->expiration_time;
940 *block_expiration = GNUNET_TIME_absolute_ntoh (msg->expiration_time);
941 memcpy (&bh[1],
942 &msg[1],
943 len);
944 b = GNUNET_HELLO_builder_from_block (*block,
945 *block_size);
946 if (NULL == b)
947 {
948 GNUNET_break_op (0);
949 GNUNET_free (*block);
950 *block_size = 0;
951 return GNUNET_SYSERR;
952 }
953 ret = verify_hello (b,
954 *block_expiration,
955 &msg->sig);
956 GNUNET_HELLO_builder_free (b);
957 if (GNUNET_SYSERR == ret)
958 {
959 GNUNET_free (*block);
960 *block_size = 0;
961 return GNUNET_SYSERR;
962 }
963 return ret;
964}