aboutsummaryrefslogtreecommitdiff
path: root/src/hello
diff options
context:
space:
mode:
Diffstat (limited to 'src/hello')
-rw-r--r--src/hello/.gitignore5
-rw-r--r--src/hello/Makefile.am69
-rw-r--r--src/hello/address.c157
-rw-r--r--src/hello/gnunet-hello.c215
-rw-r--r--src/hello/hello-ng.c197
-rw-r--r--src/hello/hello-uri.c891
-rw-r--r--src/hello/hello.c1271
-rw-r--r--src/hello/test_friend_hello.c185
-rw-r--r--src/hello/test_hello-ng.c56
-rw-r--r--src/hello/test_hello-uri.c212
-rw-r--r--src/hello/test_hello.c253
11 files changed, 0 insertions, 3511 deletions
diff --git a/src/hello/.gitignore b/src/hello/.gitignore
deleted file mode 100644
index d175d148e..000000000
--- a/src/hello/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
1gnunet-hello
2test_friend_hello
3test_hello
4test_hello-uri
5test_hello-ng
diff --git a/src/hello/Makefile.am b/src/hello/Makefile.am
deleted file mode 100644
index c04b85106..000000000
--- a/src/hello/Makefile.am
+++ /dev/null
@@ -1,69 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9lib_LTLIBRARIES = libgnunethello.la
10
11libgnunethello_la_SOURCES = \
12 hello.c \
13 address.c \
14 hello-ng.c \
15 hello-uri.c
16libgnunethello_la_LIBADD = \
17 $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \
18 $(LTLIBINTL)
19libgnunethello_la_LDFLAGS = \
20 $(GN_LIB_LDFLAGS) \
21 -version-info 1:0:1
22
23noinst_PROGRAMS = \
24 gnunet-hello
25
26check_PROGRAMS = \
27 test_hello \
28 test_hello-uri \
29 test_friend_hello \
30 test_hello-ng
31
32if ENABLE_TEST_RUN
33AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
34TESTS = $(check_PROGRAMS)
35endif
36
37test_hello_SOURCES = \
38 test_hello.c
39test_hello_LDADD = \
40 libgnunethello.la \
41 $(top_builddir)/src/util/libgnunetutil.la
42
43test_hello_ng_SOURCES = \
44 test_hello-ng.c
45test_hello_ng_LDADD = \
46 libgnunethello.la \
47 $(top_builddir)/src/util/libgnunetutil.la
48
49test_hello_uri_SOURCES = \
50 test_hello-uri.c
51test_hello_uri_LDADD = \
52 libgnunethello.la \
53 $(top_builddir)/src/util/libgnunetutil.la \
54 -lgcrypt
55
56
57test_friend_hello_SOURCES = \
58 test_friend_hello.c
59test_friend_hello_LDADD = \
60 libgnunethello.la \
61 $(top_builddir)/src/util/libgnunetutil.la
62
63gnunet_hello_SOURCES = \
64 gnunet-hello.c
65gnunet_hello_LDADD = \
66 libgnunethello.la \
67 $(top_builddir)/src/util/libgnunetutil.la
68gnunet_hello_LDFLAGS = \
69 $(GN_LIBINTL)
diff --git a/src/hello/address.c b/src/hello/address.c
deleted file mode 100644
index e22f3850f..000000000
--- a/src/hello/address.c
+++ /dev/null
@@ -1,157 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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/address.c
23 * @brief helper functions for handling addresses
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_hello_lib.h"
28#include "gnunet_util_lib.h"
29
30
31/**
32 * Check if an address has a local option set
33 *
34 * @param address the address to check
35 * @param option the respective option to check for
36 * @return #GNUNET_YES or #GNUNET_NO
37 */
38int
39GNUNET_HELLO_address_check_option (const struct GNUNET_HELLO_Address *address,
40 enum GNUNET_HELLO_AddressInfo option)
41{
42 if (option == (address->local_info & option))
43 return GNUNET_YES;
44 return GNUNET_NO;
45}
46
47
48/**
49 * Get the size of an address struct.
50 *
51 * @param address address
52 * @return the size
53 */
54size_t
55GNUNET_HELLO_address_get_size (const struct GNUNET_HELLO_Address *address)
56{
57 return sizeof(struct GNUNET_HELLO_Address) + address->address_length
58 + strlen (address->transport_name) + 1;
59}
60
61
62/**
63 * Allocate an address struct.
64 *
65 * @param peer the peer
66 * @param transport_name plugin name
67 * @param address binary address
68 * @param address_length number of bytes in 'address'
69 * @param local_info additional local information for the address
70 * @return the address struct
71 */
72struct GNUNET_HELLO_Address *
73GNUNET_HELLO_address_allocate (const struct GNUNET_PeerIdentity *peer,
74 const char *transport_name,
75 const void *address,
76 size_t address_length,
77 enum GNUNET_HELLO_AddressInfo local_info)
78{
79 struct GNUNET_HELLO_Address *addr;
80 size_t slen;
81 char *end;
82
83 slen = strlen (transport_name) + 1;
84 addr = GNUNET_malloc (sizeof(struct GNUNET_HELLO_Address)
85 + address_length + slen);
86 addr->peer = *peer;
87 addr->address = &addr[1];
88 addr->address_length = address_length;
89 addr->local_info = local_info;
90 end = (char *) &addr[1];
91 addr->transport_name = &end[address_length];
92 GNUNET_memcpy (end,
93 address,
94 address_length);
95 GNUNET_memcpy (&end[address_length],
96 transport_name,
97 slen);
98 return addr;
99}
100
101
102/**
103 * Copy an address struct.
104 *
105 * @param address address to copy
106 * @return a copy of the address struct
107 */
108struct GNUNET_HELLO_Address *
109GNUNET_HELLO_address_copy (const struct GNUNET_HELLO_Address *address)
110{
111 if (NULL == address)
112 return NULL;
113 return GNUNET_HELLO_address_allocate (&address->peer,
114 address->transport_name,
115 address->address,
116 address->address_length,
117 address->local_info);
118}
119
120
121/**
122 * Compare two addresses. Does NOT compare the peer identity,
123 * that is assumed already to match!
124 *
125 * @param a1 first address
126 * @param a2 second address
127 * @return 0 if the addresses are equal, -1 if a1<a2, 1 if a1>a2.
128 */
129int
130GNUNET_HELLO_address_cmp (const struct GNUNET_HELLO_Address *a1,
131 const struct GNUNET_HELLO_Address *a2)
132{
133 int ret;
134
135 if ((NULL == a1) &&
136 (NULL == a2))
137 return 0;
138 if (NULL == a1)
139 return 1;
140 if (NULL == a2)
141 return -1;
142 ret = strcmp (a1->transport_name, a2->transport_name);
143 if (0 != ret)
144 return ret;
145 if (a1->local_info != a2->local_info)
146 return (((int) a1->local_info) < ((int) a2->local_info)) ? -1 : 1;
147 if (a1->address_length < a2->address_length)
148 return -1;
149 if (a1->address_length > a2->address_length)
150 return 1;
151 return memcmp (a1->address,
152 a2->address,
153 a1->address_length);
154}
155
156
157/* end of address.c */
diff --git a/src/hello/gnunet-hello.c b/src/hello/gnunet-hello.c
deleted file mode 100644
index 1f110ac18..000000000
--- a/src/hello/gnunet-hello.c
+++ /dev/null
@@ -1,215 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012 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 * @file hello/gnunet-hello.c
22 * @brief change HELLO files to never expire
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_protocols.h"
27#include "gnunet_hello_lib.h"
28
29/**
30 * Closure for #add_to_buf().
31 */
32struct AddContext
33{
34 /**
35 * Where to add.
36 */
37 char *buf;
38
39 /**
40 * Maximum number of bytes left
41 */
42 size_t max;
43
44 /**
45 * Number of bytes added so far.
46 */
47 size_t ret;
48};
49
50static int address_count;
51
52
53/**
54 * Add the given address with infinite expiration to the buffer.
55 *
56 * @param cls closure
57 * @param address address to add
58 * @param expiration old expiration
59 * @return #GNUNET_OK keep iterating
60 */
61static int
62add_to_buf (void *cls,
63 const struct GNUNET_HELLO_Address *address,
64 struct GNUNET_TIME_Absolute expiration)
65{
66 struct AddContext *ac = cls;
67 size_t ret;
68
69 ret = GNUNET_HELLO_add_address (address,
70 GNUNET_TIME_UNIT_FOREVER_ABS,
71 ac->buf,
72 ac->max);
73 ac->buf += ret;
74 ac->max -= ret;
75 ac->ret += ret;
76 address_count++;
77 return GNUNET_OK;
78}
79
80
81/**
82 * Add addresses from the address list to the HELLO.
83 *
84 * @param cls the HELLO with the addresses to add
85 * @param max maximum space available
86 * @param buf where to add the addresses
87 * @return number of bytes added, 0 to terminate
88 */
89static ssize_t
90add_from_hello (void *cls, size_t max, void *buf)
91{
92 struct GNUNET_HELLO_Message **orig = cls;
93 struct AddContext ac;
94
95 if (NULL == *orig)
96 return GNUNET_SYSERR; /* already done */
97 ac.buf = buf;
98 ac.max = max;
99 ac.ret = 0;
100 GNUNET_assert (
101 NULL ==
102 GNUNET_HELLO_iterate_addresses (*orig, GNUNET_NO, &add_to_buf, &ac));
103 *orig = NULL;
104 return ac.ret;
105}
106
107
108int
109main (int argc, char *argv[])
110{
111 struct GNUNET_DISK_FileHandle *fh;
112 struct GNUNET_HELLO_Message *orig;
113 struct GNUNET_HELLO_Message *result;
114 struct GNUNET_PeerIdentity pid;
115 uint64_t fsize;
116
117 address_count = 0;
118
119 GNUNET_log_setup ("gnunet-hello", "INFO", NULL);
120 if (argc != 2)
121 {
122 fprintf (stderr, "%s", _ ("Call with name of HELLO file to modify.\n"));
123 return 1;
124 }
125 if (GNUNET_OK !=
126 GNUNET_DISK_file_size (argv[1], &fsize, GNUNET_YES, GNUNET_YES))
127 {
128 fprintf (stderr,
129 _ ("Error accessing file `%s': %s\n"),
130 argv[1],
131 strerror (errno));
132 return 1;
133 }
134 if (fsize > 65536)
135 {
136 fprintf (stderr, _ ("File `%s' is too big to be a HELLO\n"), argv[1]);
137 return 1;
138 }
139 if (fsize < sizeof(struct GNUNET_MessageHeader))
140 {
141 fprintf (stderr, _ ("File `%s' is too small to be a HELLO\n"), argv[1]);
142 return 1;
143 }
144 fh = GNUNET_DISK_file_open (argv[1],
145 GNUNET_DISK_OPEN_READ,
146 GNUNET_DISK_PERM_USER_READ);
147 if (NULL == fh)
148 {
149 fprintf (stderr,
150 _ ("Error opening file `%s': %s\n"),
151 argv[1],
152 strerror (errno));
153 return 1;
154 }
155 {
156 char buf[fsize] GNUNET_ALIGN;
157
158 GNUNET_assert (fsize == GNUNET_DISK_file_read (fh, buf, fsize));
159 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
160 orig = (struct GNUNET_HELLO_Message *) buf;
161 if ((fsize < GNUNET_HELLO_size (orig)) ||
162 (GNUNET_OK != GNUNET_HELLO_get_id (orig, &pid)))
163 {
164 fprintf (stderr,
165 _ ("Did not find well-formed HELLO in file `%s'\n"),
166 argv[1]);
167 return 1;
168 }
169 {
170 char *pids;
171
172 pids = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid.public_key);
173 fprintf (stdout, "Processing HELLO for peer `%s'\n", pids);
174 GNUNET_free (pids);
175 }
176 result = GNUNET_HELLO_create (&pid.public_key,
177 &add_from_hello,
178 &orig,
179 GNUNET_HELLO_is_friend_only (orig));
180 GNUNET_assert (NULL != result);
181 fh =
182 GNUNET_DISK_file_open (argv[1],
183 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE,
184 GNUNET_DISK_PERM_USER_READ
185 | GNUNET_DISK_PERM_USER_WRITE);
186 if (NULL == fh)
187 {
188 fprintf (stderr,
189 _ ("Error opening file `%s': %s\n"),
190 argv[1],
191 strerror (errno));
192 GNUNET_free (result);
193 return 1;
194 }
195 fsize = GNUNET_HELLO_size (result);
196 if (fsize != GNUNET_DISK_file_write (fh, result, fsize))
197 {
198 fprintf (stderr,
199 _ ("Error writing HELLO to file `%s': %s\n"),
200 argv[1],
201 strerror (errno));
202 (void) GNUNET_DISK_file_close (fh);
203 return 1;
204 }
205 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
206 }
207 fprintf (stderr,
208 _ ("Modified %u addresses, wrote %u bytes\n"),
209 address_count,
210 (unsigned int) fsize);
211 return 0;
212}
213
214
215/* end of gnunet-hello.c */
diff --git a/src/hello/hello-ng.c b/src/hello/hello-ng.c
deleted file mode 100644
index 96856a692..000000000
--- a/src/hello/hello-ng.c
+++ /dev/null
@@ -1,197 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2018 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-ng.c
23 * @brief helper library for handling HELLOs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_signatures.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_ats_service.h"
32
33GNUNET_NETWORK_STRUCT_BEGIN
34/**
35 * Binary block we sign when we sign an address.
36 */
37struct SignedAddress
38{
39 /**
40 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS
41 */
42 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
43
44 /**
45 * When was the address generated.
46 */
47 struct GNUNET_TIME_AbsoluteNBO mono_time;
48
49 /**
50 * Hash of the address.
51 */
52 struct GNUNET_HashCode addr_hash GNUNET_PACKED;
53};
54GNUNET_NETWORK_STRUCT_END
55
56/**
57 * Build address record by signing raw information with private key.
58 *
59 * @param address text address at @a communicator to sign
60 * @param nt network type of @a address
61 * @param mono_time monotonic time at which @a address was valid
62 * @param private_key signing key to use
63 * @param result[out] where to write address record (allocated)
64 * @param result_size[out] set to size of @a result
65 */
66void
67GNUNET_HELLO_sign_address (
68 const char *address,
69 enum GNUNET_NetworkType nt,
70 struct GNUNET_TIME_Absolute mono_time,
71 const struct GNUNET_CRYPTO_EddsaPrivateKey *private_key,
72 void **result,
73 size_t *result_size)
74{
75 struct SignedAddress sa;
76 struct GNUNET_CRYPTO_EddsaSignature sig;
77 char *sig_str;
78
79 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
80 sa.purpose.size = htonl (sizeof(sa));
81 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
82 GNUNET_CRYPTO_hash (address, strlen (address), &sa.addr_hash);
83 GNUNET_CRYPTO_eddsa_sign (private_key, &sa, &sig);
84 sig_str = NULL;
85 (void) GNUNET_STRINGS_base64_encode (&sig, sizeof(sig), &sig_str);
86 *result_size =
87 1 + GNUNET_asprintf ((char **) result,
88 "%s;%llu;%u;%s",
89 sig_str,
90 (unsigned long long) mono_time.abs_value_us,
91 (unsigned int) nt,
92 address);
93 GNUNET_free (sig_str);
94}
95
96
97/**
98 * Check signature and extract address record.
99 *
100 * @param raw raw signed address
101 * @param raw_size size of @a raw
102 * @param pid public key to use for signature verification
103 * @param nt[out] set to network type
104 * @param mono_time[out] when was the address generated
105 * @return NULL on error, otherwise the address
106 */
107char *
108GNUNET_HELLO_extract_address (const void *raw,
109 size_t raw_size,
110 const struct GNUNET_PeerIdentity *pid,
111 enum GNUNET_NetworkType *nt,
112 struct GNUNET_TIME_Absolute *mono_time)
113{
114 const struct GNUNET_CRYPTO_EddsaPublicKey *public_key = &pid->public_key;
115 const char *raws = raw;
116 unsigned long long raw_us = 0;
117 unsigned int raw_nt = 0;
118 const char *sc;
119 const char *sc2;
120 const char *sc3;
121 const char *raw_addr;
122 char *data = NULL;
123 struct GNUNET_TIME_Absolute raw_mono_time;
124 struct SignedAddress sa;
125 struct GNUNET_CRYPTO_EddsaSignature *sig;
126
127 if ('\0' != raws[raw_size-1])
128 {
129 GNUNET_break_op (0);
130 return NULL;
131 }
132 if (NULL == (sc = strchr (raws, ';')))
133 {
134 GNUNET_break_op (0);
135 return NULL;
136 }
137 if (NULL == (sc2 = strchr (sc + 1, ';')))
138 {
139 GNUNET_break_op (0);
140 return NULL;
141 }
142 if (NULL == (sc3 = strchr (sc2 + 1, ';')))
143 {
144 GNUNET_break_op (0);
145 return NULL;
146 }
147 if (2 != sscanf (sc + 1, "%llu;%u;%*s", &raw_us, &raw_nt))
148 {
149 GNUNET_break_op (0);
150 return NULL;
151 }
152 raw_addr = sc3 + 1;
153 raw_mono_time.abs_value_us = raw_us;
154 if (sizeof(struct GNUNET_CRYPTO_EddsaSignature) !=
155 GNUNET_STRINGS_base64_decode (raws, sc - raws, (void **) &data))
156 {
157 GNUNET_break_op (0);
158 GNUNET_free (data);
159 return NULL;
160 }
161 sig = (struct GNUNET_CRYPTO_EddsaSignature*) data;
162 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
163 sa.purpose.size = htonl (sizeof(sa));
164 sa.mono_time = GNUNET_TIME_absolute_hton (raw_mono_time);
165 GNUNET_CRYPTO_hash (raw_addr, strlen (raw_addr), &sa.addr_hash);
166 if (GNUNET_YES !=
167 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS,
168 &sa,
169 sig,
170 public_key))
171 {
172 GNUNET_break_op (0);
173 return NULL;
174 }
175 *mono_time = raw_mono_time;
176 *nt = raw_nt;
177 return GNUNET_strdup (raw_addr);
178}
179
180
181/**
182 * Given an address as a string, extract the prefix that identifies
183 * the communicator offering transmissions to that address.
184 *
185 * @param address a peer's address
186 * @return NULL if the address is mal-formed, otherwise the prefix
187 */
188char *
189GNUNET_HELLO_address_to_prefix (const char *address)
190{
191 const char *dash;
192
193 dash = strchr (address, '-');
194 if (NULL == dash)
195 return NULL;
196 return GNUNET_strndup (address, dash - address);
197}
diff --git a/src/hello/hello-uri.c b/src/hello/hello-uri.c
deleted file mode 100644
index bacaf697e..000000000
--- a/src/hello/hello-uri.c
+++ /dev/null
@@ -1,891 +0,0 @@
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/**
209 * Compute @a hash over addresses in @a builder.
210 *
211 * @param builder the builder to hash addresses of
212 * @param[out] hash where to write the hash
213 */
214static void
215hash_addresses (const struct GNUNET_HELLO_Builder *builder,
216 struct GNUNET_HashCode *hash)
217{
218 struct GNUNET_HashContext *hc;
219
220 hc = GNUNET_CRYPTO_hash_context_start ();
221 for (struct Address *a = builder->a_head;
222 NULL != a;
223 a = a->next)
224 {
225 GNUNET_CRYPTO_hash_context_read (hc,
226 a->uri,
227 a->uri_len);
228 }
229 GNUNET_CRYPTO_hash_context_finish (hc,
230 hash);
231
232}
233
234
235/**
236 * Create HELLO signature.
237 *
238 * @param builder the builder to use
239 * @param et expiration time to sign
240 * @param priv key to sign with
241 * @param[out] sig where to write the signature
242 */
243static void
244sign_hello (const struct GNUNET_HELLO_Builder *builder,
245 struct GNUNET_TIME_Timestamp et,
246 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
247 struct GNUNET_CRYPTO_EddsaSignature *sig)
248{
249 struct HelloSignaturePurpose hsp = {
250 .purpose.size = htonl (sizeof (hsp)),
251 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
252 .expiration_time = GNUNET_TIME_absolute_hton (et.abs_time)
253 };
254
255 hash_addresses (builder,
256 &hsp.h_addrs);
257 GNUNET_CRYPTO_eddsa_sign (priv,
258 &hsp,
259 sig);
260}
261
262
263/**
264 * Verify HELLO signature.
265 *
266 * @param builder the builder to use
267 * @param et expiration time to verify
268 * @param sig signature to verify
269 * @return #GNUNET_OK if everything is ok, #GNUNET_NO if the
270 * HELLO expired, #GNUNET_SYSERR if the signature is wrong
271 */
272static enum GNUNET_GenericReturnValue
273verify_hello (const struct GNUNET_HELLO_Builder *builder,
274 struct GNUNET_TIME_Absolute et,
275 const struct GNUNET_CRYPTO_EddsaSignature *sig)
276{
277 struct HelloSignaturePurpose hsp = {
278 .purpose.size = htonl (sizeof (hsp)),
279 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
280 .expiration_time = GNUNET_TIME_absolute_hton (et)
281 };
282
283 hash_addresses (builder,
284 &hsp.h_addrs);
285 if (GNUNET_OK !=
286 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_HELLO,
287 &hsp,
288 sig,
289 &builder->pid.public_key))
290 {
291 GNUNET_break_op (0);
292 return GNUNET_SYSERR;
293 }
294 if (GNUNET_TIME_absolute_is_past (et))
295 return GNUNET_NO;
296 return GNUNET_OK;
297}
298
299
300struct GNUNET_HELLO_Builder *
301GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid)
302{
303 struct GNUNET_HELLO_Builder *builder;
304
305 builder = GNUNET_new (struct GNUNET_HELLO_Builder);
306 builder->pid = *pid;
307 return builder;
308}
309
310
311void
312GNUNET_HELLO_builder_free (struct GNUNET_HELLO_Builder *builder)
313{
314 struct Address *a;
315
316 while (NULL != (a = builder->a_head))
317 {
318 GNUNET_CONTAINER_DLL_remove (builder->a_head,
319 builder->a_tail,
320 a);
321 builder->a_length--;
322 GNUNET_free (a);
323 }
324 GNUNET_assert (0 == builder->a_length);
325 GNUNET_free (builder);
326}
327
328
329struct GNUNET_HELLO_Builder *
330GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg)
331{
332 const struct HelloUriMessage *h;
333 uint16_t size = ntohs (msg->size);
334
335 if (GNUNET_MESSAGE_TYPE_HELLO_URI != ntohs (msg->type))
336 {
337 GNUNET_break (0);
338 return NULL;
339 }
340 if (sizeof (struct HelloUriMessage) > size)
341 {
342 GNUNET_break_op (0);
343 return NULL;
344 }
345 h = (const struct HelloUriMessage *) msg;
346 size -= sizeof (*h);
347 return GNUNET_HELLO_builder_from_block (&h[1],
348 size);
349}
350
351
352struct GNUNET_HELLO_Builder *
353GNUNET_HELLO_builder_from_block (const void *block,
354 size_t block_size)
355{
356 const struct BlockHeader *bh = block;
357 struct GNUNET_HELLO_Builder *b;
358
359 if (block_size < sizeof (*bh))
360 {
361 GNUNET_break_op (0);
362 return NULL;
363 }
364 b = GNUNET_HELLO_builder_new (&bh->pid);
365 block += sizeof (*bh);
366 block_size -= sizeof (*bh);
367 while (block_size > 0)
368 {
369 const void *end = memchr (block,
370 '\0',
371 block_size);
372
373 if (NULL == end)
374 {
375 GNUNET_break_op (0);
376 GNUNET_HELLO_builder_free (b);
377 return NULL;
378 }
379 if (GNUNET_OK !=
380 GNUNET_HELLO_builder_add_address (b,
381 block))
382 {
383 GNUNET_break_op (0);
384 GNUNET_HELLO_builder_free (b);
385 return NULL;
386 }
387 end++;
388 block_size -= (end - block);
389 block = end;
390 }
391 {
392 enum GNUNET_GenericReturnValue ret;
393
394 ret = verify_hello (b,
395 GNUNET_TIME_absolute_ntoh (bh->expiration_time),
396 &bh->sig);
397 GNUNET_break (GNUNET_SYSERR != ret);
398 if (GNUNET_OK != ret)
399 {
400 GNUNET_HELLO_builder_free (b);
401 return NULL;
402 }
403 }
404 return b;
405}
406
407
408struct GNUNET_HELLO_Builder *
409GNUNET_HELLO_builder_from_url (const char *url)
410{
411 const char *q;
412 const char *s1;
413 const char *s2;
414 struct GNUNET_PeerIdentity pid;
415 struct GNUNET_CRYPTO_EddsaSignature sig;
416 struct GNUNET_TIME_Absolute et;
417 size_t len;
418 struct GNUNET_HELLO_Builder *b;
419
420 if (0 != strncasecmp (url,
421 "gnunet://hello/",
422 strlen ("gnunet://hello/")))
423 return NULL;
424 url += strlen ("gnunet://hello/");
425 s1 = strchr (url, '/');
426 if (NULL == s1)
427 {
428 GNUNET_break_op (0);
429 return NULL;
430 }
431 s2 = strchr (s1 + 1, '/');
432 if (NULL == s1)
433 {
434 GNUNET_break_op (0);
435 return NULL;
436 }
437 q = strchr (url, '?');
438 if (NULL == q)
439 q = url + strlen (url);
440 if (GNUNET_OK !=
441 GNUNET_STRINGS_string_to_data (url,
442 s1 - url,
443 &pid,
444 sizeof(pid)))
445 {
446 GNUNET_break_op (0);
447 return NULL;
448 }
449 if (GNUNET_OK !=
450 GNUNET_STRINGS_string_to_data (s1 + 1,
451 s2 - (s1 + 1),
452 &sig,
453 sizeof(sig)))
454 {
455 GNUNET_break_op (0);
456 return NULL;
457 }
458 {
459 unsigned long long sec;
460 char dummy = '?';
461
462 if ( (0 == sscanf (s2 + 1,
463 "%llu%c",
464 &sec,
465 &dummy)) ||
466 ('?' != dummy) )
467 {
468 GNUNET_break_op (0);
469 return NULL;
470 }
471 et = GNUNET_TIME_absolute_from_s (sec);
472 }
473
474 b = GNUNET_HELLO_builder_new (&pid);
475 len = strlen (q);
476 while (len > 0)
477 {
478 const char *eq;
479 const char *amp;
480 char *addr = NULL;
481 char *uri;
482
483 /* skip ?/& separator */
484 len--;
485 q++;
486 eq = strchr (q, '=');
487 if ( (eq == q) ||
488 (NULL == eq) )
489 {
490 GNUNET_break_op (0);
491 GNUNET_HELLO_builder_free (b);
492 return NULL;
493 }
494 amp = strchr (eq, '&');
495 if (NULL == amp)
496 amp = &q[len];
497 GNUNET_STRINGS_urldecode (eq + 1,
498 amp - (eq + 1),
499 &addr);
500 if ( (NULL == addr) ||
501 (0 == strlen (addr)) )
502 {
503 GNUNET_free (addr);
504 GNUNET_break_op (0);
505 GNUNET_HELLO_builder_free (b);
506 return NULL;
507 }
508 GNUNET_asprintf (&uri,
509 "%.*s://%s",
510 (int) (eq - q),
511 q,
512 addr);
513 GNUNET_free (addr);
514 if (GNUNET_OK !=
515 GNUNET_HELLO_builder_add_address (b,
516 uri))
517 {
518 GNUNET_break_op (0);
519 GNUNET_free (uri);
520 GNUNET_HELLO_builder_free (b);
521 return NULL;
522 }
523 GNUNET_free (uri);
524 /* move to next URL */
525 len -= (amp - q);
526 q = amp;
527 }
528
529 {
530 enum GNUNET_GenericReturnValue ret;
531
532 ret = verify_hello (b,
533 et,
534 &sig);
535 GNUNET_break (GNUNET_SYSERR != ret);
536 if (GNUNET_OK != ret)
537 {
538 GNUNET_HELLO_builder_free (b);
539 return NULL;
540 }
541 }
542 return b;
543}
544
545
546struct GNUNET_MQ_Envelope *
547GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder,
548 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
549{
550 struct GNUNET_MQ_Envelope *env;
551 struct HelloUriMessage *msg;
552 size_t blen;
553
554 if (builder->a_length > UINT16_MAX)
555 {
556 GNUNET_break (0);
557 return NULL;
558 }
559 blen = 0;
560 GNUNET_assert (GNUNET_NO ==
561 GNUNET_HELLO_builder_to_block (builder,
562 priv,
563 NULL,
564 &blen));
565 env = GNUNET_MQ_msg_extra (msg,
566 blen,
567 GNUNET_MESSAGE_TYPE_HELLO_URI);
568 msg->url_counter = htonl ((uint16_t) builder->a_length);
569 GNUNET_assert (GNUNET_OK ==
570 GNUNET_HELLO_builder_to_block (builder,
571 priv,
572 &msg[1],
573 &blen));
574 return env;
575}
576
577
578struct GNUNET_MessageHeader *
579GNUNET_HELLO_builder_to_dht_hello_msg (
580 const struct GNUNET_HELLO_Builder *builder,
581 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
582{
583 struct DhtHelloMessage *msg;
584 size_t blen;
585
586 if (builder->a_length > UINT16_MAX)
587 {
588 GNUNET_break (0);
589 return NULL;
590 }
591 blen = 0;
592 GNUNET_assert (GNUNET_NO ==
593 GNUNET_HELLO_builder_to_block (builder,
594 priv,
595 NULL,
596 &blen));
597 GNUNET_assert (blen < UINT16_MAX);
598 GNUNET_assert (blen >= sizeof (struct BlockHeader));
599 {
600 char buf[blen] GNUNET_ALIGN;
601 const struct BlockHeader *block = (const struct BlockHeader *) buf;
602
603 GNUNET_assert (GNUNET_OK ==
604 GNUNET_HELLO_builder_to_block (builder,
605 priv,
606 buf,
607 &blen));
608 msg = GNUNET_malloc (sizeof (*msg)
609 + blen
610 - sizeof (*block));
611 msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO);
612 msg->header.size = htons (sizeof (*msg)
613 + blen
614 - sizeof (*block));
615 memcpy (&msg[1],
616 &block[1],
617 blen - sizeof (*block));
618 msg->sig = block->sig;
619 msg->expiration_time = block->expiration_time;
620 }
621 msg->url_counter = htonl ((uint16_t) builder->a_length);
622 return &msg->header;
623}
624
625
626char *
627GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
628 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
629{
630 struct GNUNET_CRYPTO_EddsaSignature sig;
631 struct GNUNET_TIME_Timestamp et;
632 char *result;
633 char *pids;
634 char *sigs;
635 const char *sep = "?";
636
637 et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
638 sign_hello (builder,
639 et,
640 priv,
641 &sig);
642 pids = GNUNET_STRINGS_data_to_string_alloc (&builder->pid,
643 sizeof (builder->pid));
644 sigs = GNUNET_STRINGS_data_to_string_alloc (&sig,
645 sizeof (sig));
646 GNUNET_asprintf (&result,
647 "gnunet://hello/%s/%s/%llu",
648 pids,
649 sigs,
650 (unsigned long long) GNUNET_TIME_timestamp_to_s (et));
651 GNUNET_free (sigs);
652 GNUNET_free (pids);
653 for (struct Address *a = builder->a_head;
654 NULL != a;
655 a = a->next)
656 {
657 char *ue;
658 char *tmp;
659 int pfx_len;
660 const char *eou;
661
662 eou = strstr (a->uri,
663 "://");
664 if (NULL == eou)
665 {
666 GNUNET_break (0);
667 GNUNET_free (result);
668 return NULL;
669 }
670 pfx_len = eou - a->uri;
671 eou += 3;
672 GNUNET_STRINGS_urlencode (eou,
673 a->uri_len - 4 - pfx_len,
674 &ue);
675 GNUNET_asprintf (&tmp,
676 "%s%s%.*s=%s",
677 result,
678 sep,
679 pfx_len,
680 a->uri,
681 ue);
682 GNUNET_free (ue);
683 GNUNET_free (result);
684 result = tmp;
685 sep = "&";
686 }
687 return result;
688}
689
690
691enum GNUNET_GenericReturnValue
692GNUNET_HELLO_builder_to_block (const struct GNUNET_HELLO_Builder *builder,
693 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
694 void *block,
695 size_t *block_size)
696{
697 struct BlockHeader bh;
698 size_t needed = sizeof (bh);
699 char *pos;
700 struct GNUNET_TIME_Timestamp et;
701
702 for (struct Address *a = builder->a_head;
703 NULL != a;
704 a = a->next)
705 {
706 GNUNET_assert (needed + a->uri_len > needed);
707 needed += a->uri_len;
708 }
709 if ( (NULL == block) ||
710 (needed < *block_size) )
711 {
712 *block_size = needed;
713 return GNUNET_NO;
714 }
715 bh.pid = builder->pid;
716 et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
717 bh.expiration_time = GNUNET_TIME_absolute_hton (et.abs_time);
718 sign_hello (builder,
719 et,
720 priv,
721 &bh.sig);
722 memcpy (block,
723 &bh,
724 sizeof (bh));
725 pos = block + sizeof (bh);
726 for (struct Address *a = builder->a_head;
727 NULL != a;
728 a = a->next)
729 {
730 memcpy (pos,
731 a->uri,
732 a->uri_len);
733 pos += a->uri_len;
734 }
735 *block_size = needed;
736 return GNUNET_OK;
737}
738
739
740enum GNUNET_GenericReturnValue
741GNUNET_HELLO_builder_add_address (struct GNUNET_HELLO_Builder *builder,
742 const char *address)
743{
744 size_t alen = strlen (address) + 1;
745 struct Address *a;
746 const char *e;
747
748 if (NULL == (e = strstr (address,
749 "://")))
750 {
751 GNUNET_break_op (0);
752 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
753 "Invalid address `%s'\n",
754 address);
755 return GNUNET_SYSERR;
756 }
757 if (e == address)
758 {
759 GNUNET_break_op (0);
760 return GNUNET_SYSERR;
761 }
762 for (const char *p = address; p != e; p++)
763 if ( (! isalpha ((unsigned char) *p)) &&
764 ('+' != *p) )
765 {
766 GNUNET_break_op (0);
767 return GNUNET_SYSERR;
768 }
769 /* check for duplicates */
770 for (a = builder->a_head;
771 NULL != a;
772 a = a->next)
773 if (0 == strcmp (address,
774 a->uri))
775 return GNUNET_NO;
776 a = GNUNET_malloc (sizeof (struct Address) + alen);
777 a->uri_len = alen;
778 memcpy (&a[1],
779 address,
780 alen);
781 a->uri = (const char *) &a[1];
782 GNUNET_CONTAINER_DLL_insert_tail (builder->a_head,
783 builder->a_tail,
784 a);
785 builder->a_length++;
786 return GNUNET_OK;
787}
788
789
790enum GNUNET_GenericReturnValue
791GNUNET_HELLO_builder_del_address (struct GNUNET_HELLO_Builder *builder,
792 const char *address)
793{
794 struct Address *a;
795
796 /* check for duplicates */
797 for (a = builder->a_head;
798 NULL != a;
799 a = a->next)
800 if (0 == strcmp (address,
801 a->uri))
802 break;
803 if (NULL == a)
804 return GNUNET_NO;
805 GNUNET_CONTAINER_DLL_remove (builder->a_head,
806 builder->a_tail,
807 a);
808 builder->a_length--;
809 GNUNET_free (a);
810 return GNUNET_OK;
811}
812
813
814void
815GNUNET_HELLO_builder_iterate (const struct GNUNET_HELLO_Builder *builder,
816 struct GNUNET_PeerIdentity *pid,
817 GNUNET_HELLO_UriCallback uc,
818 void *uc_cls)
819{
820 struct Address *nxt;
821
822 *pid = builder->pid;
823 if (NULL == uc)
824 return;
825 for (struct Address *a = builder->a_head;
826 NULL != a;
827 a = nxt)
828 {
829 nxt = a->next;
830 uc (uc_cls,
831 a->uri);
832 }
833}
834
835
836enum GNUNET_GenericReturnValue
837GNUNET_HELLO_dht_msg_to_block (const struct GNUNET_MessageHeader *hello,
838 const struct GNUNET_PeerIdentity *pid,
839 void **block,
840 size_t *block_size,
841 struct GNUNET_TIME_Absolute *block_expiration)
842{
843 const struct DhtHelloMessage *msg
844 = (const struct DhtHelloMessage *) hello;
845 uint16_t len = ntohs (hello->size);
846 struct BlockHeader *bh;
847 struct GNUNET_HELLO_Builder *b;
848 enum GNUNET_GenericReturnValue ret;
849
850 if (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO != ntohs (hello->type))
851 {
852 GNUNET_break (0);
853 return GNUNET_SYSERR;
854 }
855 if (len < sizeof (*msg))
856 {
857 GNUNET_break_op (0);
858 return GNUNET_SYSERR;
859 }
860 len -= sizeof (*msg);
861 *block_size = len + sizeof (*bh);
862 *block = GNUNET_malloc (*block_size);
863 bh = *block;
864 bh->pid = *pid;
865 bh->sig = msg->sig;
866 bh->expiration_time = msg->expiration_time;
867 *block_expiration = GNUNET_TIME_absolute_ntoh (msg->expiration_time);
868 memcpy (&bh[1],
869 &msg[1],
870 len);
871 b = GNUNET_HELLO_builder_from_block (*block,
872 *block_size);
873 if (NULL == b)
874 {
875 GNUNET_break_op (0);
876 GNUNET_free (*block);
877 *block_size = 0;
878 return GNUNET_SYSERR;
879 }
880 ret = verify_hello (b,
881 *block_expiration,
882 &msg->sig);
883 GNUNET_HELLO_builder_free (b);
884 if (GNUNET_SYSERR == ret)
885 {
886 GNUNET_free (*block);
887 *block_size = 0;
888 return GNUNET_SYSERR;
889 }
890 return ret;
891}
diff --git a/src/hello/hello.c b/src/hello/hello.c
deleted file mode 100644
index 12b576ceb..000000000
--- a/src/hello/hello.c
+++ /dev/null
@@ -1,1271 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015 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.c
23 * @brief helper library for handling HELLOs
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 */
27#include "platform.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_transport_plugin.h"
32
33/**
34 * Context used for building our own URI.
35 */
36struct GNUNET_HELLO_ComposeUriContext
37{
38 /**
39 * Final URI.
40 */
41 char *uri;
42
43 /**
44 * Function for finding transport plugins by name.
45 */
46 GNUNET_HELLO_TransportPluginsFind plugins_find;
47};
48
49
50/**
51 * Context for #add_address_to_hello().
52 */
53struct GNUNET_HELLO_ParseUriContext
54{
55 /**
56 * Position in the URI with the next address to parse.
57 */
58 const char *pos;
59
60 /**
61 * Set to #GNUNET_SYSERR to indicate parse errors.
62 */
63 int ret;
64
65 /**
66 * Counter
67 */
68 unsigned int counter_total;
69
70 /**
71 * Counter skipped addresses
72 */
73 unsigned int counter_added;
74
75 /**
76 * Function for finding transport plugins by name.
77 */
78 GNUNET_HELLO_TransportPluginsFind plugins_find;
79};
80
81
82/**
83 * Return HELLO type
84 *
85 * @param h HELLO Message to test
86 * @return #GNUNET_YES for friend-only or #GNUNET_NO otherwise
87 */
88int
89GNUNET_HELLO_is_friend_only (const struct GNUNET_HELLO_Message *h)
90{
91 if (GNUNET_YES == ntohl (h->friend_only))
92 return GNUNET_YES;
93 return GNUNET_NO;
94}
95
96
97/**
98 * Copy the given address information into
99 * the given buffer using the format of HELLOs.
100 *
101 * @param address the address
102 * @param expiration expiration for the @a address
103 * @param target where to copy the @a address
104 * @param max maximum number of bytes to copy to target
105 * @return number of bytes copied, 0 if
106 * the target buffer was not big enough.
107 */
108size_t
109GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address,
110 struct GNUNET_TIME_Absolute expiration,
111 char *target,
112 size_t max)
113{
114 uint16_t alen;
115 size_t slen;
116 struct GNUNET_TIME_AbsoluteNBO exp;
117
118 slen = strlen (address->transport_name) + 1;
119 if (slen + sizeof(uint16_t) + sizeof(struct GNUNET_TIME_AbsoluteNBO)
120 + address->address_length > max)
121 return 0;
122 exp = GNUNET_TIME_absolute_hton (expiration);
123 alen = htons ((uint16_t) address->address_length);
124 GNUNET_memcpy (target, address->transport_name, slen);
125 GNUNET_memcpy (&target[slen], &alen, sizeof(uint16_t));
126 slen += sizeof(uint16_t);
127 GNUNET_memcpy (&target[slen], &exp, sizeof(struct GNUNET_TIME_AbsoluteNBO));
128 slen += sizeof(struct GNUNET_TIME_AbsoluteNBO);
129 GNUNET_memcpy (&target[slen], address->address, address->address_length);
130 slen += address->address_length;
131 return slen;
132}
133
134
135/**
136 * Get the size of an address entry in a HELLO message.
137 *
138 * @param buf pointer to the start of the address entry
139 * @param max maximum size of the entry (end of @a buf)
140 * @param ralen set to the address length
141 * @return size of the entry, or 0 if @a max is not large enough
142 */
143static size_t
144get_hello_address_size (const char *buf,
145 size_t max,
146 uint16_t *ralen)
147{
148 const char *pos;
149 uint16_t alen;
150 size_t left;
151 size_t slen;
152
153 left = max;
154 pos = buf;
155 slen = 1;
156 while ((left > 0) && ('\0' != *pos))
157 {
158 left--;
159 pos++;
160 slen++;
161 }
162 if (0 == left)
163 {
164 /* 0-termination not found */
165 GNUNET_break_op (0);
166 return 0;
167 }
168 pos++;
169 if (left < sizeof(uint16_t) + sizeof(struct GNUNET_TIME_AbsoluteNBO))
170 {
171 /* not enough space for addrlen */
172 GNUNET_break_op (0);
173 return 0;
174 }
175 GNUNET_memcpy (&alen, pos, sizeof(uint16_t));
176 alen = ntohs (alen);
177 *ralen = alen;
178 slen += alen + sizeof(uint16_t) + sizeof(struct GNUNET_TIME_AbsoluteNBO);
179 if (max < slen)
180 {
181 /* not enough space for addr */
182 GNUNET_break_op (0);
183 return 0;
184 }
185 return slen;
186}
187
188
189/**
190 * Construct a HELLO message given the public key,
191 * expiration time and an iterator that spews the
192 * transport addresses.
193 *
194 * If friend only is set to #GNUNET_YES we create a FRIEND_HELLO which
195 * will not be gossiped to other peers.
196 *
197 * @param public_key public key to include in the HELLO
198 * @param addrgen callback to invoke to get addresses
199 * @param addrgen_cls closure for @a addrgen
200 * @param friend_only should the returned HELLO be only visible to friends?
201 * @return the hello message
202 */
203struct GNUNET_HELLO_Message *
204GNUNET_HELLO_create (const struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
205 GNUNET_HELLO_GenerateAddressListCallback addrgen,
206 void *addrgen_cls,
207 int friend_only)
208{
209 char buffer[GNUNET_MAX_MESSAGE_SIZE - 1 - 256
210 - sizeof(struct GNUNET_HELLO_Message)];
211 size_t max;
212 size_t used;
213 size_t ret;
214 struct GNUNET_HELLO_Message *hello;
215
216 GNUNET_assert (NULL != public_key);
217 GNUNET_assert ((GNUNET_YES == friend_only) ||
218 (GNUNET_NO == friend_only));
219 max = sizeof(buffer);
220 used = 0;
221 if (NULL != addrgen)
222 {
223 while (GNUNET_SYSERR != (ret = addrgen (addrgen_cls,
224 max,
225 &buffer[used])))
226 {
227 max -= ret;
228 used += ret;
229 }
230 }
231 hello = GNUNET_malloc (sizeof(struct GNUNET_HELLO_Message) + used);
232 hello->header.type = htons (GNUNET_MESSAGE_TYPE_HELLO);
233 hello->header.size = htons (sizeof(struct GNUNET_HELLO_Message) + used);
234 hello->friend_only = htonl (friend_only);
235 hello->publicKey = *public_key;
236 GNUNET_memcpy (&hello[1],
237 buffer,
238 used);
239 return hello;
240}
241
242
243/**
244 * Iterate over all of the addresses in the HELLO.
245 *
246 * @param msg HELLO to iterate over
247 * @param return_modified if a modified copy should be returned,
248 * otherwise NULL will be returned
249 * @param it iterator to call on each address
250 * @param it_cls closure for @a it
251 * @return modified HELLO message
252 */
253struct GNUNET_HELLO_Message *
254GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg,
255 int return_modified,
256 GNUNET_HELLO_AddressIterator it,
257 void *it_cls)
258{
259 struct GNUNET_HELLO_Address address;
260 uint16_t msize;
261 struct GNUNET_HELLO_Message *ret;
262 const char *inptr;
263 size_t insize;
264 size_t esize;
265 size_t wpos;
266 char *woff;
267 uint16_t alen;
268 struct GNUNET_TIME_AbsoluteNBO expire;
269 int iret;
270
271 msize = GNUNET_HELLO_size (msg);
272 if ((msize < sizeof(struct GNUNET_HELLO_Message)) ||
273 (ntohs (msg->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
274 {
275 GNUNET_break_op (0);
276 return NULL;
277 }
278 ret = NULL;
279 if (return_modified)
280 {
281 ret = GNUNET_malloc (msize);
282 GNUNET_memcpy (ret,
283 msg,
284 msize);
285 }
286 inptr = (const char *) &msg[1];
287 insize = msize - sizeof(struct GNUNET_HELLO_Message);
288 wpos = 0;
289 woff = (NULL != ret) ? (char *) &ret[1] : NULL;
290 address.peer.public_key = msg->publicKey;
291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292 "HELLO has %u bytes of address data\n",
293 (unsigned int) insize);
294
295 while (insize > 0)
296 {
297 esize = get_hello_address_size (inptr,
298 insize,
299 &alen);
300 if (0 == esize)
301 {
302 GNUNET_break (0);
303 GNUNET_free (ret);
304 return NULL;
305 }
306 /* need GNUNET_memcpy() due to possibility of misalignment */
307 GNUNET_memcpy (&expire,
308 &inptr[esize - alen - sizeof(struct
309 GNUNET_TIME_AbsoluteNBO)],
310 sizeof(struct GNUNET_TIME_AbsoluteNBO));
311 address.address = &inptr[esize - alen];
312 address.address_length = alen;
313 address.transport_name = inptr;
314 address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
315 iret = it (it_cls,
316 &address,
317 GNUNET_TIME_absolute_ntoh (expire));
318 if (GNUNET_SYSERR == iret)
319 break;
320 if ((GNUNET_OK == iret) &&
321 (NULL != ret))
322 {
323 /* copy address over */
324 GNUNET_memcpy (woff,
325 inptr,
326 esize);
327 woff += esize;
328 wpos += esize;
329 }
330 insize -= esize;
331 inptr += esize;
332 }
333 if (NULL != ret)
334 ret->header.size = ntohs (sizeof(struct GNUNET_HELLO_Message) + wpos);
335 return ret;
336}
337
338
339/**
340 * Closure for #get_match_exp().
341 */
342struct ExpireContext
343{
344 /**
345 * Address we are looking for.
346 */
347 const struct GNUNET_HELLO_Address *address;
348
349 /**
350 * Set to #GNUNET_YES if we found the @e address.
351 */
352 int found;
353
354 /**
355 * Set to the expiration of the match if @e found is #GNUNET_YES.
356 */
357 struct GNUNET_TIME_Absolute expiration;
358};
359
360
361/**
362 * Store the expiration time of an address that matches the template.
363 *
364 * @param cls the `struct ExpireContext`
365 * @param address address to match against the template
366 * @param expiration expiration time of @a address, to store in @a cls
367 * @return #GNUNET_SYSERR if we found a matching address, #GNUNET_OK otherwise
368 */
369static int
370get_match_exp (void *cls,
371 const struct GNUNET_HELLO_Address *address,
372 struct GNUNET_TIME_Absolute expiration)
373{
374 struct ExpireContext *ec = cls;
375
376 if (0 != GNUNET_HELLO_address_cmp (address,
377 ec->address))
378 return GNUNET_OK;
379 ec->found = GNUNET_YES;
380 ec->expiration = expiration;
381 return GNUNET_SYSERR; /* done here */
382}
383
384
385/**
386 * Context for a #GNUNET_HELLO_Merge operation.
387 */
388struct MergeContext
389{
390 /**
391 * First HELLO we are merging.
392 */
393 const struct GNUNET_HELLO_Message *h1;
394
395 /**
396 * Second HELLO we are merging.
397 */
398 const struct GNUNET_HELLO_Message *h2;
399
400 /**
401 * Either @e h1 or @e h2, used when copying
402 * to compare against (so we only copy the
403 * most recent entry).
404 */
405 const struct GNUNET_HELLO_Message *other;
406
407 /**
408 * Buffer where we copy to.
409 */
410 char *buf;
411
412 /**
413 * Number of bytes allocated in @e buf
414 */
415 size_t max;
416
417 /**
418 * Current (write) offset in @e buf.
419 */
420 size_t ret;
421
422 /**
423 * Should we copy addresses with an identical value
424 * and expiration time in @e other, or do we only
425 * copy addresses with strictly later expiration times?
426 */
427 int take_equal;
428};
429
430
431/**
432 * Append the address @a address to the buffer from
433 * the merge context IF it is more recent than equivalent
434 * addresses in `other`.
435 *
436 * @param cls the `struct MergeContext`
437 * @param address the HELLO address we might copy
438 * @param expiration expiration time for @a address
439 * @return always #GNUNET_OK
440 */
441static int
442copy_latest (void *cls,
443 const struct GNUNET_HELLO_Address *address,
444 struct GNUNET_TIME_Absolute expiration)
445{
446 struct MergeContext *mc = cls;
447 struct ExpireContext ec;
448
449 ec.address = address;
450 ec.found = GNUNET_NO;
451 /* check if address exists in other */
452 GNUNET_HELLO_iterate_addresses (mc->other,
453 GNUNET_NO,
454 &get_match_exp,
455 &ec);
456 if ((GNUNET_NO == ec.found) ||
457 (ec.expiration.abs_value_us < expiration.abs_value_us) ||
458 ((ec.expiration.abs_value_us == expiration.abs_value_us) &&
459 (GNUNET_YES == mc->take_equal)))
460 {
461 /* copy address to buffer */
462 mc->ret +=
463 GNUNET_HELLO_add_address (address,
464 expiration,
465 &mc->buf[mc->ret],
466 mc->max - mc->ret);
467 }
468 return GNUNET_OK;
469}
470
471
472/**
473 * Function called to build the HELLO during
474 * #GNUNET_HELLO_merge() by merging addresses from
475 * two original HELLOs.
476 *
477 * @param cls the `struct MergeContext`
478 * @param max number of bytes we can write at most in @a buf
479 * @param buf where to copy the addresses
480 * @return #GNUNET_SYSERR to end iteration, otherwise number of bytes written to @a buf
481 */
482static ssize_t
483merge_addr (void *cls,
484 size_t max,
485 void *buf)
486{
487 struct MergeContext *mc = cls;
488
489 if (NULL == mc->h1)
490 return GNUNET_SYSERR; /* Stop iteration */
491 mc->ret = 0;
492 mc->max = max;
493 mc->buf = buf;
494 mc->take_equal = GNUNET_NO;
495 mc->other = mc->h2;
496 /* copy addresses from h1, if strictly larger expiration than h2 */
497 GNUNET_HELLO_iterate_addresses (mc->h1,
498 GNUNET_NO,
499 &copy_latest,
500 mc);
501 mc->take_equal = GNUNET_YES;
502 mc->other = mc->h1;
503 /* copy addresses from h2, if larger or equal expiration than h1 */
504 GNUNET_HELLO_iterate_addresses (mc->h2,
505 GNUNET_NO,
506 &copy_latest,
507 mc);
508 /* set marker to stop iteration */
509 mc->h1 = NULL;
510 return mc->ret;
511}
512
513
514/**
515 * Construct a HELLO message by merging the
516 * addresses in two existing HELLOs (which
517 * must be for the same peer).
518 *
519 * @param h1 first HELLO message
520 * @param h2 the second HELLO message
521 * @return the combined HELLO message
522 */
523struct GNUNET_HELLO_Message *
524GNUNET_HELLO_merge (const struct GNUNET_HELLO_Message *h1,
525 const struct GNUNET_HELLO_Message *h2)
526{
527 struct MergeContext mc = { h1, h2, NULL, NULL, 0, 0, 0 };
528 int friend_only;
529
530 if (h1->friend_only != h2->friend_only)
531 friend_only = GNUNET_YES; /* One of the HELLOs is friend only */
532 else
533 friend_only = ntohl (h1->friend_only); /* Both HELLO's have the same type */
534
535 return GNUNET_HELLO_create (&h1->publicKey,
536 &merge_addr,
537 &mc,
538 friend_only);
539}
540
541
542/**
543 * Context used in #GNUNET_HELLO_iterate_new_addresses() to
544 * figure out which addresses are in fact 'new'.
545 */
546struct DeltaContext
547{
548 /**
549 * We should ignore addresses that expire before this time.
550 */
551 struct GNUNET_TIME_Absolute expiration_limit;
552
553 /**
554 * Function to call on addresses that are indeed new.
555 */
556 GNUNET_HELLO_AddressIterator it;
557
558 /**
559 * Closure for @e it.
560 */
561 void *it_cls;
562
563 /**
564 * HELLO with known addresses, addresses in this HELLO
565 * we must always ignore.
566 */
567 const struct GNUNET_HELLO_Message *old_hello;
568};
569
570
571/**
572 * Check if the given address is 'new', and if so, call
573 * the iterator. Compares the existing address against
574 * addresses in the context's `old_hello` and calls the
575 * iterator on those that are new (and not expired).
576 *
577 * @param cls the `struct DeltaContext`
578 * @param address an address to check whether it is new
579 * @param expiration expiration time for @a address
580 * @return #GNUNET_YES if the address is ignored, otherwise
581 * whatever the iterator returned.
582 */
583static int
584delta_match (void *cls,
585 const struct GNUNET_HELLO_Address *address,
586 struct GNUNET_TIME_Absolute expiration)
587{
588 struct DeltaContext *dc = cls;
589 int ret;
590 struct ExpireContext ec;
591
592 ec.address = address;
593 ec.found = GNUNET_NO;
594 GNUNET_HELLO_iterate_addresses (dc->old_hello,
595 GNUNET_NO,
596 &get_match_exp,
597 &ec);
598 if ((GNUNET_YES == ec.found) &&
599 ((ec.expiration.abs_value_us > expiration.abs_value_us) ||
600 (ec.expiration.abs_value_us >= dc->expiration_limit.abs_value_us)))
601 return GNUNET_YES; /* skip: found and boring */
602 ret = dc->it (dc->it_cls,
603 address,
604 expiration);
605 return ret;
606}
607
608
609/**
610 * Iterate over addresses in @a new_hello that are NOT already present
611 * in @a old_hello. Note that if the address is present in @a old_hello
612 * but the expiration time in @a new_hello is more recent, the iterator
613 * is also called.
614 *
615 * @param new_hello a HELLO message
616 * @param old_hello a HELLO message
617 * @param expiration_limit ignore addresses in @a old_hello
618 * that expired before the given time stamp
619 * @param it iterator to call on each address
620 * @param it_cls closure for @a it
621 */
622void
623GNUNET_HELLO_iterate_new_addresses (const struct
624 GNUNET_HELLO_Message *new_hello,
625 const struct
626 GNUNET_HELLO_Message *old_hello,
627 struct GNUNET_TIME_Absolute
628 expiration_limit,
629 GNUNET_HELLO_AddressIterator it,
630 void *it_cls)
631{
632 struct DeltaContext dc;
633
634 dc.expiration_limit = expiration_limit;
635 dc.it = it;
636 dc.it_cls = it_cls;
637 dc.old_hello = old_hello;
638 GNUNET_assert (NULL ==
639 GNUNET_HELLO_iterate_addresses (new_hello,
640 GNUNET_NO,
641 &delta_match,
642 &dc));
643}
644
645
646/**
647 * Return the size of the given HELLO message.
648 * @param hello to inspect
649 * @return the size, 0 if HELLO is invalid
650 */
651uint16_t
652GNUNET_HELLO_size (const struct GNUNET_HELLO_Message *hello)
653{
654 uint16_t ret = ntohs (hello->header.size);
655
656 if ((ret < sizeof(struct GNUNET_HELLO_Message)) ||
657 (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
658 return 0;
659 return ret;
660}
661
662
663/**
664 * Get the peer identity from a HELLO message.
665 *
666 * @param hello the hello message
667 * @param peer where to store the peer's identity
668 * @return #GNUNET_SYSERR if the HELLO was malformed
669 */
670int
671GNUNET_HELLO_get_id (const struct GNUNET_HELLO_Message *hello,
672 struct GNUNET_PeerIdentity *peer)
673{
674 uint16_t ret = ntohs (hello->header.size);
675
676 if ((ret < sizeof(struct GNUNET_HELLO_Message)) ||
677 (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
678 return GNUNET_SYSERR;
679 peer->public_key = hello->publicKey;
680 return GNUNET_OK;
681}
682
683
684/**
685 * Get the header from a HELLO message, used so other code
686 * can correctly send HELLO messages.
687 *
688 * @param hello the hello message
689 *
690 * @return header or NULL if the HELLO was malformed
691 */
692struct GNUNET_MessageHeader *
693GNUNET_HELLO_get_header (struct GNUNET_HELLO_Message *hello)
694{
695 uint16_t ret = ntohs (hello->header.size);
696
697 if ((ret < sizeof(struct GNUNET_HELLO_Message)) ||
698 (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
699 return NULL;
700
701 return &hello->header;
702}
703
704
705/**
706 * Context used for comparing HELLOs in #GNUNET_HELLO_equals().
707 */
708struct EqualsContext
709{
710 /**
711 * Addresses that expired before this date are ignored for
712 * the comparison.
713 */
714 struct GNUNET_TIME_Absolute expiration_limit;
715
716 /**
717 * Earliest expiration time for which we found a match
718 * with a difference in expiration times.
719 * At this time, the two HELLOs may start to diverge.
720 */
721 struct GNUNET_TIME_Absolute result;
722
723 /**
724 * HELLO message to compare against. (First set to the second
725 * HELLO, then set to the first HELLO.)
726 */
727 const struct GNUNET_HELLO_Message *ref;
728
729 /**
730 * Address we are currently looking for.
731 */
732 const struct GNUNET_HELLO_Address *address;
733
734 /**
735 * Expiration time of @e address.
736 */
737 struct GNUNET_TIME_Absolute expiration;
738
739 /**
740 * Did we find the address we were looking for?
741 */
742 int found;
743};
744
745
746/**
747 * Check if the given address matches the address we are currently
748 * looking for. If so, sets `found` to #GNUNET_YES and, if the
749 * expiration times for the two addresses differ, updates `result` to
750 * the minimum of our @a expiration and the existing value
751 *
752 * @param cls the `struct EqualsContext`
753 * @param address address from the reference HELLO
754 * @param expiration expiration time for @a address
755 * @return #GNUNET_YES if the address is expired or does not match
756 * #GNUNET_SYSERR if the address does match.
757 */
758static int
759find_other_matching (void *cls,
760 const struct GNUNET_HELLO_Address *address,
761 struct GNUNET_TIME_Absolute expiration)
762{
763 struct EqualsContext *ec = cls;
764
765 if (expiration.abs_value_us < ec->expiration_limit.abs_value_us)
766 return GNUNET_YES;
767 if (0 == GNUNET_HELLO_address_cmp (address, ec->address))
768 {
769 ec->found = GNUNET_YES;
770 if (expiration.abs_value_us < ec->expiration.abs_value_us)
771 ec->result = GNUNET_TIME_absolute_min (expiration,
772 ec->result);
773 return GNUNET_SYSERR;
774 }
775 return GNUNET_YES;
776}
777
778
779/**
780 * Helper function for #GNUNET_HELLO_equals(). Checks
781 * if the given @a address exists also in the other HELLO;
782 * if not, the result time is set to zero and the iteration
783 * is aborted.
784 *
785 * @param cls the `struct EqualsContext`
786 * @param address address to locate
787 * @param expiration expiration time of the current address
788 * @return #GNUNET_OK if the address exists or is expired,
789 * #GNUNET_SYSERR if it was not found
790 */
791static int
792find_matching (void *cls,
793 const struct GNUNET_HELLO_Address *address,
794 struct GNUNET_TIME_Absolute expiration)
795{
796 struct EqualsContext *ec = cls;
797
798 if (expiration.abs_value_us < ec->expiration_limit.abs_value_us)
799 return GNUNET_OK; /* expired, we don't care */
800 ec->address = address;
801 ec->expiration = expiration;
802 ec->found = GNUNET_NO;
803 GNUNET_HELLO_iterate_addresses (ec->ref,
804 GNUNET_NO,
805 &find_other_matching,
806 ec);
807 if (GNUNET_NO == ec->found)
808 {
809 /* not found, we differ *now* */
810 ec->result = GNUNET_TIME_UNIT_ZERO_ABS;
811 return GNUNET_SYSERR;
812 }
813 return GNUNET_OK;
814}
815
816
817/**
818 * Test if two HELLO messages contain the same addresses.
819 * If they only differ in expiration time, the lowest
820 * expiration time larger than @a now where they differ
821 * is returned.
822 *
823 * @param h1 first HELLO message
824 * @param h2 the second HELLO message
825 * @param now time to use for deciding which addresses have
826 * expired and should not be considered at all
827 * @return absolute time forever if the two HELLOs are
828 * totally identical; smallest timestamp >= @a now if
829 * they only differ in timestamps;
830 * zero if the some addresses with expirations >= @a now
831 * do not match at all
832 */
833struct GNUNET_TIME_Absolute
834GNUNET_HELLO_equals (const struct GNUNET_HELLO_Message *h1,
835 const struct GNUNET_HELLO_Message *h2,
836 struct GNUNET_TIME_Absolute now)
837{
838 struct EqualsContext ec;
839
840 if (h1->header.type != h2->header.type)
841 return GNUNET_TIME_UNIT_ZERO_ABS;
842 if (0 !=
843 GNUNET_memcmp (&h1->publicKey,
844 &h2->publicKey))
845 return GNUNET_TIME_UNIT_ZERO_ABS;
846 ec.expiration_limit = now;
847 ec.result = GNUNET_TIME_UNIT_FOREVER_ABS;
848 ec.ref = h2;
849 GNUNET_HELLO_iterate_addresses (h1,
850 GNUNET_NO,
851 &find_matching,
852 &ec);
853 if (ec.result.abs_value_us == GNUNET_TIME_UNIT_ZERO.rel_value_us)
854 return ec.result;
855 ec.ref = h1;
856 GNUNET_HELLO_iterate_addresses (h2,
857 GNUNET_NO,
858 &find_matching,
859 &ec);
860 return ec.result;
861}
862
863
864/**
865 * Iterator to find the time when the last address will expire.
866 * Updates the maximum value stored in @a cls.
867 *
868 * @param cls where to store the max, a `struct GNUNET_TIME_Absolute`
869 * @param address an address (ignored)
870 * @param expiration expiration time for @a address
871 * @return #GNUNET_OK (always)
872 */
873static int
874find_max_expire (void *cls,
875 const struct GNUNET_HELLO_Address *address,
876 struct GNUNET_TIME_Absolute expiration)
877{
878 struct GNUNET_TIME_Absolute *max = cls;
879
880 *max = GNUNET_TIME_absolute_max (*max, expiration);
881 return GNUNET_OK;
882}
883
884
885/**
886 * When does the last address in the given HELLO expire?
887 *
888 * @param msg HELLO to inspect
889 * @return time the last address expires, 0 if there are no addresses in the HELLO
890 */
891struct GNUNET_TIME_Absolute
892GNUNET_HELLO_get_last_expiration (const struct GNUNET_HELLO_Message *msg)
893{
894 struct GNUNET_TIME_Absolute ret;
895
896 ret = GNUNET_TIME_UNIT_ZERO_ABS;
897 GNUNET_HELLO_iterate_addresses (msg,
898 GNUNET_NO,
899 &find_max_expire,
900 &ret);
901 return ret;
902}
903
904
905/**
906 * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER".
907 * The specific structure of "IDENTIFIER" depends on the module and
908 * maybe differentiated into additional subcategories if applicable.
909 * This module only deals with hello identifiers (MODULE = "hello").
910 * <p>
911 *
912 * The concrete URI format is:
913 *
914 * "gnunet://hello/PEER[+YYYYMMDDHHMMSS+<TYPE>+<ADDRESS>]...".
915 * These URIs can be used to add a peer record to peerinfo service.
916 * PEER is the string representation of peer's public key.
917 * YYYYMMDDHHMMSS is the expiration date.
918 * TYPE is a transport type.
919 * ADDRESS is the address, its format depends upon the transport type.
920 * The concrete transport types and corresponding address formats are:
921 *
922 * <ul><li>
923 *
924 * <TCP|UDP>!IPADDRESS
925 * IPVDDRESS is either IPV4 .-delimited address in form of XXX.XXX.XXX.XXX:PPPPP
926 * or IPV6 :-delimited address with '[' and ']' (according to RFC2732):
927 * [XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX]:PPPPP
928 * PPPPP is the port number. May be 0.
929 *
930 * </li><li>
931 *
932 * [add SMTP, HTTP and other addresses here]
933 *
934 * </li></ul>
935 *
936 * The encoding for hexadecimal values is defined in the crypto_hash.c
937 * module in the gnunetutil library and discussed there.
938 *
939 * Examples:
940 *
941 * gnunet://hello/V8XXK9GAN5ZJFRFQP8MQX3D83BZTSBQVHKWWD0JPE63Z821906EG+20120302010059+TCP+192.168.0.1:2086+TCP+64.23.8.174:0
942 * gnunet://hello/V8XXK9GAN5ZJFRFQP8MQX3D83BZTSBQVHKWWD0JPE63Z821906EG+20120302010059+TCP+[2001:db8:85a3:8d3:1319:8a2e:370:7348]:2086
943 *
944 * <p>
945 */
946
947
948/**
949 * Function that is called on each address of this peer.
950 * Expands the corresponding URI string.
951 *
952 * @param cls the `struct GNUNET_HELLO_ComposeUriContext`
953 * @param address address to add
954 * @param expiration expiration time for the address
955 * @return #GNUNET_OK (continue iteration).
956 */
957static int
958add_address_to_uri (void *cls,
959 const struct GNUNET_HELLO_Address *address,
960 struct GNUNET_TIME_Absolute expiration)
961{
962 struct GNUNET_HELLO_ComposeUriContext *ctx = cls;
963 struct GNUNET_TRANSPORT_PluginFunctions *papi;
964 const char *addr;
965 char *ret;
966 char *addr_dup;
967 char *pos;
968 char tbuf[16] = "";
969 char *client_str = "_client";
970 struct tm *t;
971 time_t seconds;
972
973 papi = ctx->plugins_find (address->transport_name);
974 if (NULL == papi)
975 {
976 /* Not an error - we might just not have the right plugin. */
977 return GNUNET_OK;
978 }
979 if (NULL == papi->address_to_string)
980 {
981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
982 "URI conversion not implemented for plugin `%s'\n",
983 address->transport_name);
984 return GNUNET_OK;
985 }
986 addr = papi->address_to_string (papi->cls,
987 address->address,
988 address->address_length);
989 if ((NULL == addr) ||
990 (0 == strlen (addr)))
991 return GNUNET_OK;
992
993 addr_dup = GNUNET_strdup (addr);
994 if (NULL != (pos = strstr (addr_dup, "_server")))
995 GNUNET_memcpy (pos,
996 client_str,
997 strlen (client_str)); /* Replace all server addresses with client addresses */
998
999 seconds = expiration.abs_value_us / 1000LL / 1000LL;
1000 t = gmtime (&seconds);
1001
1002 GNUNET_asprintf (&ret,
1003 "%s%c%s%c%s%c%s",
1004 ctx->uri,
1005 GNUNET_HELLO_URI_SEP,
1006 strftime (tbuf,
1007 sizeof(tbuf),
1008 "%Y%m%d%H%M%S",
1009 t) ? tbuf : "0",
1010 GNUNET_HELLO_URI_SEP,
1011 address->transport_name,
1012 GNUNET_HELLO_URI_SEP,
1013 addr_dup);
1014 GNUNET_free (addr_dup);
1015 GNUNET_free (ctx->uri);
1016 ctx->uri = ret;
1017 return GNUNET_OK;
1018}
1019
1020
1021/**
1022 * Compose a hello URI string from a hello message.
1023 *
1024 * @param hello Hello message
1025 * @param plugins_find Function to find transport plugins by name
1026 * @return Hello URI string
1027 */
1028char *
1029GNUNET_HELLO_compose_uri (const struct GNUNET_HELLO_Message *hello,
1030 GNUNET_HELLO_TransportPluginsFind plugins_find)
1031{
1032 struct GNUNET_HELLO_ComposeUriContext ctx;
1033 char *pkey;
1034
1035 ctx.plugins_find = plugins_find;
1036 pkey = GNUNET_CRYPTO_eddsa_public_key_to_string (&hello->publicKey);
1037 GNUNET_asprintf (&ctx.uri,
1038 "%s%s",
1039 (GNUNET_YES == GNUNET_HELLO_is_friend_only (hello))
1040 ? GNUNET_FRIEND_HELLO_URI_PREFIX
1041 : GNUNET_HELLO_URI_PREFIX,
1042 pkey);
1043 GNUNET_free (pkey);
1044 GNUNET_HELLO_iterate_addresses (hello,
1045 GNUNET_NO,
1046 &add_address_to_uri,
1047 &ctx);
1048 return ctx.uri;
1049}
1050
1051
1052/* ************************* Parse HELLO URI ********************* */
1053
1054
1055/**
1056 * We're building a HELLO. Parse the next address from the
1057 * parsing context and append it.
1058 *
1059 * @param cls the `struct GNUNET_HELLO_ParseUriContext`
1060 * @param max number of bytes available for HELLO construction
1061 * @param buffer where to copy the next address (in binary format)
1062 * @return number of bytes added to buffer, #GNUNET_SYSERR on error
1063 */
1064static ssize_t
1065add_address_to_hello (void *cls,
1066 size_t max,
1067 void *buffer)
1068{
1069 struct GNUNET_HELLO_ParseUriContext *ctx = cls;
1070 const char *tname;
1071 const char *address;
1072 char *uri_address;
1073 const char *end;
1074 char *plugin_name;
1075 struct tm expiration_time;
1076 time_t expiration_seconds;
1077 struct GNUNET_TIME_Absolute expire;
1078 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1079 void *addr;
1080 size_t addr_len;
1081 struct GNUNET_HELLO_Address haddr;
1082 ssize_t ret;
1083
1084 if (NULL == ctx->pos)
1085 return GNUNET_SYSERR;
1086 if (GNUNET_HELLO_URI_SEP != ctx->pos[0])
1087 {
1088 ctx->ret = GNUNET_SYSERR;
1089 GNUNET_break (0);
1090 return GNUNET_SYSERR;
1091 }
1092 ctx->pos++;
1093
1094 if (('0' == ctx->pos[0]) &&
1095 (GNUNET_HELLO_URI_SEP == ctx->pos[1]))
1096 {
1097 expire = GNUNET_TIME_UNIT_FOREVER_ABS;
1098 tname = ctx->pos + 1;
1099 }
1100 else
1101 {
1102 memset (&expiration_time, 0, sizeof(expiration_time));
1103 tname = strptime (ctx->pos,
1104 "%Y%m%d%H%M%S",
1105 &expiration_time);
1106 if (NULL == tname)
1107 {
1108 ctx->ret = GNUNET_SYSERR;
1109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1110 _ (
1111 "Failed to parse HELLO message: missing expiration time\n"));
1112 GNUNET_break (0);
1113 return GNUNET_SYSERR;
1114 }
1115
1116 expiration_seconds = mktime (&expiration_time);
1117 if (expiration_seconds == (time_t) -1)
1118 {
1119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1120 _ (
1121 "Failed to parse HELLO message: invalid expiration time\n"));
1122 ctx->ret = GNUNET_SYSERR;
1123 GNUNET_break (0);
1124 return GNUNET_SYSERR;
1125 }
1126 expire.abs_value_us = expiration_seconds * 1000LL * 1000LL;
1127 }
1128 if (GNUNET_HELLO_URI_SEP != tname[0])
1129 {
1130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1131 _ ("Failed to parse HELLO message: malformed\n"));
1132 ctx->ret = GNUNET_SYSERR;
1133 GNUNET_break (0);
1134 return GNUNET_SYSERR;
1135 }
1136 tname++;
1137 address = strchr (tname,
1138 (int) GNUNET_HELLO_URI_SEP);
1139 if (NULL == address)
1140 {
1141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1142 _ (
1143 "Failed to parse HELLO message: missing transport plugin\n"));
1144 ctx->ret = GNUNET_SYSERR;
1145 GNUNET_break (0);
1146 return GNUNET_SYSERR;
1147 }
1148 address++;
1149 end = strchr (address, (int) GNUNET_HELLO_URI_SEP);
1150 ctx->pos = end;
1151 ctx->counter_total++;
1152 plugin_name = GNUNET_strndup (tname, address - (tname + 1));
1153 papi = ctx->plugins_find (plugin_name);
1154 if (NULL == papi)
1155 {
1156 /* Not an error - we might just not have the right plugin.
1157 * Skip this part, advance to the next one and recurse.
1158 * But only if this is not the end of string.
1159 */
1160 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1161 _ ("Plugin `%s' not found, skipping address\n"),
1162 plugin_name);
1163 GNUNET_free (plugin_name);
1164 return 0;
1165 }
1166 if (NULL == papi->string_to_address)
1167 {
1168 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1169 _ ("Plugin `%s' does not support URIs yet\n"),
1170 plugin_name);
1171 GNUNET_free (plugin_name);
1172 GNUNET_break (0);
1173 return 0;
1174 }
1175 uri_address = GNUNET_strndup (address, end - address);
1176 if (GNUNET_OK !=
1177 papi->string_to_address (papi->cls,
1178 uri_address,
1179 strlen (uri_address) + 1,
1180 &addr,
1181 &addr_len))
1182 {
1183 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1184 _ ("Failed to parse `%s' as an address for plugin `%s'\n"),
1185 uri_address,
1186 plugin_name);
1187 GNUNET_free (plugin_name);
1188 GNUNET_free (uri_address);
1189 return 0;
1190 }
1191 GNUNET_free (uri_address);
1192 /* address.peer is unset - not used by add_address() */
1193 haddr.address_length = addr_len;
1194 haddr.address = addr;
1195 haddr.transport_name = plugin_name;
1196 ret = GNUNET_HELLO_add_address (&haddr,
1197 expire,
1198 buffer,
1199 max);
1200 ctx->counter_added++;
1201 GNUNET_free (addr);
1202 GNUNET_free (plugin_name);
1203 return ret;
1204}
1205
1206
1207/**
1208 * Parse a hello URI string to a hello message.
1209 *
1210 * @param uri URI string to parse
1211 * @param pubkey Pointer to struct where public key is parsed
1212 * @param hello Pointer to struct where hello message is parsed
1213 * @param plugins_find Function to find transport plugins by name
1214 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the URI was invalid, #GNUNET_NO on other errors
1215 */
1216int
1217GNUNET_HELLO_parse_uri (const char *uri,
1218 struct GNUNET_CRYPTO_EddsaPublicKey *pubkey,
1219 struct GNUNET_HELLO_Message **hello,
1220 GNUNET_HELLO_TransportPluginsFind plugins_find)
1221{
1222 const char *pks;
1223 const char *exc;
1224 int friend_only;
1225 struct GNUNET_HELLO_ParseUriContext ctx;
1226
1227 if (0 == strncmp (uri,
1228 GNUNET_HELLO_URI_PREFIX,
1229 strlen (GNUNET_HELLO_URI_PREFIX)))
1230 {
1231 pks = &uri[strlen (GNUNET_HELLO_URI_PREFIX)];
1232 friend_only = GNUNET_NO;
1233 }
1234 else if (0 == strncmp (uri,
1235 GNUNET_FRIEND_HELLO_URI_PREFIX,
1236 strlen (GNUNET_FRIEND_HELLO_URI_PREFIX)))
1237 {
1238 pks = &uri[strlen (GNUNET_FRIEND_HELLO_URI_PREFIX)];
1239 friend_only = GNUNET_YES;
1240 }
1241 else
1242 return GNUNET_SYSERR;
1243 exc = strchr (pks, GNUNET_HELLO_URI_SEP);
1244
1245 if (GNUNET_OK !=
1246 GNUNET_STRINGS_string_to_data (pks,
1247 (NULL == exc) ? strlen (pks) : (exc - pks),
1248 (unsigned char *) pubkey,
1249 sizeof(*pubkey)))
1250 return GNUNET_SYSERR;
1251
1252 ctx.pos = exc;
1253 ctx.ret = GNUNET_OK;
1254 ctx.counter_total = 0;
1255 ctx.counter_added = 0;
1256 ctx.plugins_find = plugins_find;
1257 *hello = GNUNET_HELLO_create (pubkey,
1258 &add_address_to_hello,
1259 &ctx,
1260 friend_only);
1261
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263 "HELLO URI contained %u addresses, added %u addresses\n",
1264 ctx.counter_total,
1265 ctx.counter_added);
1266
1267 return ctx.ret;
1268}
1269
1270
1271/* end of hello.c */
diff --git a/src/hello/test_friend_hello.c b/src/hello/test_friend_hello.c
deleted file mode 100644
index 1b092c0b8..000000000
--- a/src/hello/test_friend_hello.c
+++ /dev/null
@@ -1,185 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009 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 * @file hello/test_friend_hello.c
22 * @brief test for hello.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_hello_lib.h"
27
28
29static ssize_t
30my_addr_gen (void *cls,
31 size_t max,
32 void *buf)
33{
34 unsigned int *i = cls;
35 size_t ret;
36 struct GNUNET_HELLO_Address address;
37
38 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
39 "DEBUG: my_addr_gen called with i = %d\n", *i);
40 if (0 == *i)
41 return GNUNET_SYSERR; /* Stop iteration */
42 memset (&address.peer, 0, sizeof(struct GNUNET_PeerIdentity));
43 address.address = "address_information";
44 address.transport_name = "test";
45 address.address_length = *i;
46 ret =
47 GNUNET_HELLO_add_address (&address, GNUNET_TIME_absolute_get (), buf,
48 max);
49 (*i)--;
50 return ret;
51}
52
53
54static int
55check_addr (void *cls,
56 const struct GNUNET_HELLO_Address *address,
57 struct GNUNET_TIME_Absolute expiration)
58{
59 unsigned int *i = cls;
60
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "DEBUG: check_addr called with i = %d and addrlen = %u\n",
63 *i, (unsigned int) address->address_length);
64 GNUNET_assert (address->address_length > 0);
65 GNUNET_assert (*i & (1 << (address->address_length - 1)));
66 *i -= (1 << (address->address_length - 1));
67 GNUNET_assert (0 ==
68 strncmp ("address_information", address->address,
69 address->address_length));
70 GNUNET_assert (0 == strcmp ("test", address->transport_name));
71 return GNUNET_OK;
72}
73
74
75static int
76remove_some (void *cls,
77 const struct GNUNET_HELLO_Address *address,
78 struct GNUNET_TIME_Absolute expiration)
79{
80 unsigned int *i = cls;
81
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
83 "DEBUG: remove_some called with i = %d and addrlen = %u\n",
84 *i, (unsigned int) address->address_length);
85 GNUNET_assert (address->address_length > 0);
86 if (*i & (1 << (address->address_length - 1)))
87 {
88 *i -= (1 << (address->address_length - 1));
89 return GNUNET_NO;
90 }
91 return GNUNET_OK;
92}
93
94
95int
96main (int argc, char *argv[])
97{
98 struct GNUNET_HELLO_Message *msg1;
99 struct GNUNET_HELLO_Message *msg2;
100 struct GNUNET_HELLO_Message *msg3;
101 struct GNUNET_CRYPTO_EddsaPublicKey publicKey;
102 struct GNUNET_TIME_Absolute startup_time;
103 unsigned int i;
104
105 GNUNET_log_setup ("test-hello", "DEBUG", NULL);
106 startup_time = GNUNET_TIME_absolute_get ();
107 memset (&publicKey, 42, sizeof(publicKey));
108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
109 "Testing HELLO creation (without addresses)...\n");
110 i = 0;
111 msg1 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i, GNUNET_YES);
112 GNUNET_assert (msg1 != NULL);
113 GNUNET_assert (0 < GNUNET_HELLO_size (msg1));
114
115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116 "Testing address iteration (empty set)...\n");
117 GNUNET_assert (NULL ==
118 GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr,
119 &i));
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "Testing HELLO creation (with one address)...\n");
122 i = 1;
123 msg2 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i, GNUNET_YES);
124 GNUNET_assert (msg2 != NULL);
125 GNUNET_assert (GNUNET_HELLO_size (msg1) < GNUNET_HELLO_size (msg2));
126
127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
128 "Testing address iteration (one address)...\n");
129 i = 1;
130 GNUNET_assert (NULL ==
131 GNUNET_HELLO_iterate_addresses (msg2, GNUNET_NO, &check_addr,
132 &i));
133 GNUNET_assert (i == 0);
134 GNUNET_free (msg1);
135
136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
137 "Testing HELLO creation (with two addresses)...\n");
138 i = 2;
139 msg3 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i, GNUNET_YES);
140 GNUNET_assert (msg3 != NULL);
141 GNUNET_assert (GNUNET_HELLO_size (msg2) < GNUNET_HELLO_size (msg3));
142
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Testing address iteration (two addresses)...\n");
145 i = 3;
146 GNUNET_assert (NULL ==
147 GNUNET_HELLO_iterate_addresses (msg3, GNUNET_NO, &check_addr,
148 &i));
149 GNUNET_assert (i == 0);
150
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152 "Testing HELLO merge...\n");
153 msg1 = GNUNET_HELLO_merge (msg2, msg3);
154 GNUNET_assert (GNUNET_HELLO_size (msg1) == GNUNET_HELLO_size (msg3));
155
156 i = 3;
157 GNUNET_assert (NULL ==
158 GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr,
159 &i));
160 GNUNET_assert (i == 0);
161 GNUNET_free (msg1);
162
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Testing address iteration to copy HELLO...\n");
165 i = 2;
166 msg1 = GNUNET_HELLO_iterate_addresses (msg3, GNUNET_YES, &remove_some, &i);
167 GNUNET_assert (msg1 != NULL);
168 GNUNET_assert (i == 0);
169 i = 1;
170 GNUNET_assert (NULL ==
171 GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr,
172 &i));
173 GNUNET_assert (i == 0);
174 GNUNET_free (msg1);
175
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "Testing delta address iteration...\n");
178 i = 2;
179 GNUNET_HELLO_iterate_new_addresses (msg3, msg2, startup_time, &check_addr,
180 &i);
181 GNUNET_assert (i == 0);
182 GNUNET_free (msg2);
183 GNUNET_free (msg3);
184 return 0; /* testcase passed */
185}
diff --git a/src/hello/test_hello-ng.c b/src/hello/test_hello-ng.c
deleted file mode 100644
index 4ace9439f..000000000
--- a/src/hello/test_hello-ng.c
+++ /dev/null
@@ -1,56 +0,0 @@
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#include "platform.h"
21#include "gnunet_util_lib.h"
22#include "gnunet_nt_lib.h"
23#include "gnunet_hello_lib.h"
24
25int
26main (int argc,
27 char *argv[])
28{
29 struct GNUNET_CRYPTO_EddsaPublicKey pubKey;
30 struct GNUNET_CRYPTO_EddsaPrivateKey privKey;
31 struct GNUNET_PeerIdentity pid;
32 struct GNUNET_TIME_Absolute t = GNUNET_TIME_absolute_get ();
33 char *res;
34 size_t res_len;
35 enum GNUNET_NetworkType nt;
36
37 GNUNET_CRYPTO_eddsa_key_create (&privKey);
38 GNUNET_CRYPTO_eddsa_key_get_public (&privKey,
39 &pubKey);
40 pid.public_key = pubKey;
41 GNUNET_HELLO_sign_address ("127.0.0.1:8080",
42 GNUNET_NT_LAN,
43 t,
44 &privKey,
45 (void**) &res,
46 &res_len);
47 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
48 "%s\n", res);
49 GNUNET_assert (NULL !=
50 GNUNET_HELLO_extract_address ((void**) res,
51 res_len,
52 &pid,
53 &nt,
54 &t));
55 return 0;
56}
diff --git a/src/hello/test_hello-uri.c b/src/hello/test_hello-uri.c
deleted file mode 100644
index 7e70d6763..000000000
--- a/src/hello/test_hello-uri.c
+++ /dev/null
@@ -1,212 +0,0 @@
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 * @file hello/test_hello-uri.c
22 * @brief test for helper library for handling URI-based HELLOs
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_signatures.h"
27#include "gnunet_hello_uri_lib.h"
28#include "gnunet_util_lib.h"
29
30
31/**
32 * Check for expected URIs.
33 *
34 * @param cls a `unsigned int*`, bitmask set to found URIs
35 * @param uri URI to check for
36 */
37static void
38check_uris (void *cls,
39 const char *uri)
40{
41 unsigned int *found = cls;
42
43 if (0 == strcmp (uri,
44 "test://address"))
45 *found |= 1;
46 else if (0 == strcmp (uri,
47 "test://more"))
48 *found |= 2;
49 else
50 *found = (unsigned int) -1;
51}
52
53
54int
55main (int argc,
56 char *argv[])
57{
58 struct GNUNET_PeerIdentity pid;
59 struct GNUNET_HELLO_Builder *b;
60 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
61
62 GNUNET_log_setup ("test-hell-uri",
63 "WARNING",
64 NULL);
65 GNUNET_CRYPTO_eddsa_key_create (&priv);
66 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
67 &pid.public_key);
68 b = GNUNET_HELLO_builder_new (&pid);
69 GNUNET_assert (GNUNET_SYSERR ==
70 GNUNET_HELLO_builder_add_address (b,
71 "invalid"));
72 GNUNET_assert (GNUNET_SYSERR ==
73 GNUNET_HELLO_builder_add_address (b,
74 "i%v://bla"));
75 GNUNET_assert (GNUNET_SYSERR ==
76 GNUNET_HELLO_builder_add_address (b,
77 "://empty"));
78 GNUNET_assert (GNUNET_OK ==
79 GNUNET_HELLO_builder_add_address (b,
80 "test://address"));
81 GNUNET_assert (GNUNET_NO ==
82 GNUNET_HELLO_builder_add_address (b,
83 "test://address"));
84 GNUNET_assert (GNUNET_OK ==
85 GNUNET_HELLO_builder_add_address (b,
86 "test://more"));
87 {
88 void *block;
89 size_t block_size = 0;
90 struct GNUNET_HELLO_Builder *b2;
91 struct GNUNET_PeerIdentity p2;
92 unsigned int found;
93
94 GNUNET_assert (GNUNET_NO ==
95 GNUNET_HELLO_builder_to_block (b,
96 &priv,
97 NULL,
98 &block_size));
99 GNUNET_assert (GNUNET_NO ==
100 GNUNET_HELLO_builder_to_block (b,
101 &priv,
102 NULL,
103 &block_size));
104 GNUNET_assert (0 != block_size);
105 block = GNUNET_malloc (block_size);
106 GNUNET_assert (GNUNET_OK ==
107 GNUNET_HELLO_builder_to_block (b,
108 &priv,
109 block,
110 &block_size));
111 b2 = GNUNET_HELLO_builder_from_block (block,
112 block_size);
113 GNUNET_free (block);
114 GNUNET_assert (NULL != b2);
115 found = 0;
116 GNUNET_HELLO_builder_iterate (b2,
117 &p2,
118 &check_uris,
119 &found);
120 GNUNET_assert (3 == found);
121 GNUNET_assert (0 ==
122 GNUNET_memcmp (&p2,
123 &pid));
124 GNUNET_HELLO_builder_free (b2);
125 }
126
127 {
128 char *url;
129 struct GNUNET_HELLO_Builder *b2;
130 struct GNUNET_PeerIdentity p2;
131 unsigned int found;
132
133 url = GNUNET_HELLO_builder_to_url (b,
134 &priv);
135 b2 = GNUNET_HELLO_builder_from_url (url);
136 GNUNET_free (url);
137 GNUNET_assert (NULL != b2);
138 found = 0;
139 GNUNET_HELLO_builder_iterate (b2,
140 &p2,
141 &check_uris,
142 &found);
143 GNUNET_assert (3 == found);
144 GNUNET_assert (0 ==
145 GNUNET_memcmp (&p2,
146 &pid));
147 GNUNET_HELLO_builder_free (b2);
148 }
149
150 {
151 struct GNUNET_MQ_Envelope *env;
152 struct GNUNET_HELLO_Builder *b2;
153 struct GNUNET_PeerIdentity p2;
154 unsigned int found;
155
156 env = GNUNET_HELLO_builder_to_env (b,
157 &priv);
158 b2 = GNUNET_HELLO_builder_from_msg (GNUNET_MQ_env_get_msg (env));
159 GNUNET_free (env);
160 GNUNET_assert (NULL != b2);
161 found = 0;
162 GNUNET_HELLO_builder_iterate (b2,
163 &p2,
164 &check_uris,
165 &found);
166 GNUNET_assert (3 == found);
167 GNUNET_assert (0 ==
168 GNUNET_memcmp (&p2,
169 &pid));
170 GNUNET_HELLO_builder_free (b2);
171 }
172
173 GNUNET_HELLO_builder_free (b);
174
175 GNUNET_CRYPTO_mpi_print_unsigned (priv.d,
176 sizeof (priv.d),
177 GCRYMPI_CONST_ONE);
178 priv.d[0] &= 248;
179 priv.d[31] &= 127;
180 priv.d[31] |= 64;
181 {
182 char *buf;
183
184 buf = GNUNET_STRINGS_data_to_string_alloc (&priv,
185 sizeof (priv));
186 fprintf (stderr,
187 "PK: %s\n",
188 buf);
189 GNUNET_free (buf);
190 }
191 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
192 &pid.public_key);
193 b = GNUNET_HELLO_builder_new (&pid);
194 GNUNET_assert (GNUNET_OK ==
195 GNUNET_HELLO_builder_add_address (b,
196 "a://first"));
197 GNUNET_assert (GNUNET_OK ==
198 GNUNET_HELLO_builder_add_address (b,
199 "b://second"));
200 {
201 char *url;
202
203 url = GNUNET_HELLO_builder_to_url (b,
204 &priv);
205 fprintf (stderr,
206 "TV: %s\n",
207 url);
208 GNUNET_free (url);
209 }
210
211 return 0;
212}
diff --git a/src/hello/test_hello.c b/src/hello/test_hello.c
deleted file mode 100644
index 8631d2af3..000000000
--- a/src/hello/test_hello.c
+++ /dev/null
@@ -1,253 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009, 2015 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 * @file hello/test_hello.c
22 * @brief test for hello.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_hello_lib.h"
27
28
29/**
30 *
31 *
32 * @param cls
33 * @param max
34 * @param buf
35 * @return
36 */
37static ssize_t
38my_addr_gen (void *cls,
39 size_t max,
40 void *buf)
41{
42 unsigned int *i = cls;
43 size_t ret;
44 struct GNUNET_HELLO_Address address;
45
46 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
47 "DEBUG: my_addr_gen called with i = %d\n",
48 *i);
49 if (0 == *i)
50 return GNUNET_SYSERR;
51 memset (&address.peer, 0, sizeof(struct GNUNET_PeerIdentity));
52 address.address = "address_information";
53 address.transport_name = "test";
54 address.address_length = *i;
55 ret = GNUNET_HELLO_add_address (&address,
56 GNUNET_TIME_absolute_get (),
57 buf,
58 max);
59 (*i)--;
60 return ret;
61}
62
63
64/**
65 *
66 *
67 * @param cls
68 * @param address
69 * @param expiration
70 * @return
71 */
72static int
73check_addr (void *cls,
74 const struct GNUNET_HELLO_Address *address,
75 struct GNUNET_TIME_Absolute expiration)
76{
77 unsigned int *i = cls;
78
79 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
80 "DEBUG: check_addr called with i = %d and addrlen = %u\n",
81 *i,
82 (unsigned int) address->address_length);
83 GNUNET_assert (address->address_length > 0);
84 GNUNET_assert (*i & (1 << (address->address_length - 1)));
85 *i -= (1 << (address->address_length - 1));
86 GNUNET_assert (0 ==
87 strncmp ("address_information",
88 address->address,
89 address->address_length));
90 GNUNET_assert (0 == strcmp ("test",
91 address->transport_name));
92 return GNUNET_OK;
93}
94
95
96/**
97 *
98 *
99 * @param cls
100 * @param address
101 * @param expiration
102 * @return
103 */
104static int
105remove_some (void *cls,
106 const struct GNUNET_HELLO_Address *address,
107 struct GNUNET_TIME_Absolute expiration)
108{
109 unsigned int *i = cls;
110
111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
112 "DEBUG: remove_some called with i = %d and addrlen = %u\n",
113 *i,
114 (unsigned int) address->address_length);
115 GNUNET_assert (address->address_length > 0);
116 if (*i & (1 << (address->address_length - 1)))
117 {
118 *i -= (1 << (address->address_length - 1));
119 return GNUNET_NO;
120 }
121 return GNUNET_OK;
122}
123
124
125int
126main (int argc,
127 char *argv[])
128{
129 struct GNUNET_HELLO_Message *msg1;
130 struct GNUNET_HELLO_Message *msg2;
131 struct GNUNET_HELLO_Message *msg3;
132 struct GNUNET_CRYPTO_EddsaPublicKey publicKey;
133 struct GNUNET_PeerIdentity pid;
134 struct GNUNET_TIME_Absolute startup_time;
135 unsigned int i;
136
137 GNUNET_log_setup ("test-hello",
138 "DEBUG",
139 NULL);
140 startup_time = GNUNET_TIME_absolute_get ();
141 memset (&publicKey, 42, sizeof(publicKey));
142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143 "Testing HELLO creation (without addresses)...\n");
144 i = 0;
145 msg1 = GNUNET_HELLO_create (&publicKey,
146 &my_addr_gen,
147 &i,
148 GNUNET_NO);
149 GNUNET_assert (msg1 != NULL);
150 GNUNET_assert (0 < GNUNET_HELLO_size (msg1));
151
152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
153 "Testing address iteration (empty set)...\n");
154 GNUNET_assert (NULL ==
155 GNUNET_HELLO_iterate_addresses (msg1,
156 GNUNET_NO,
157 &check_addr,
158 &i));
159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160 "Testing HELLO creation (with one address)...\n");
161 i = 1;
162 msg2 = GNUNET_HELLO_create (&publicKey,
163 &my_addr_gen,
164 &i,
165 GNUNET_NO);
166 GNUNET_assert (msg2 != NULL);
167 GNUNET_assert (GNUNET_HELLO_size (msg1) < GNUNET_HELLO_size (msg2));
168
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
170 "Testing address iteration (one address)...\n");
171 i = 1;
172 GNUNET_assert (NULL ==
173 GNUNET_HELLO_iterate_addresses (msg2,
174 GNUNET_NO,
175 &check_addr,
176 &i));
177 GNUNET_assert (i == 0);
178
179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
180 "Testing get_key from HELLO...\n");
181 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (msg2, &pid));
182 GNUNET_assert (0 == GNUNET_memcmp (&publicKey,
183 &pid.public_key));
184 GNUNET_free (msg1);
185
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187 "Testing HELLO creation (with two addresses)...\n");
188 i = 2;
189 msg3 = GNUNET_HELLO_create (&publicKey,
190 &my_addr_gen,
191 &i,
192 GNUNET_NO);
193 GNUNET_assert (msg3 != NULL);
194 GNUNET_assert (GNUNET_HELLO_size (msg2) < GNUNET_HELLO_size (msg3));
195
196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
197 "Testing address iteration (two addresses)...\n");
198 i = 3;
199 GNUNET_assert (NULL ==
200 GNUNET_HELLO_iterate_addresses (msg3,
201 GNUNET_NO,
202 &check_addr,
203 &i));
204 GNUNET_assert (i == 0);
205
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 "Testing HELLO merge...\n");
208 msg1 = GNUNET_HELLO_merge (msg2, msg3);
209 GNUNET_assert (GNUNET_HELLO_size (msg1) == GNUNET_HELLO_size (msg3));
210
211 i = 3;
212 GNUNET_assert (NULL ==
213 GNUNET_HELLO_iterate_addresses (msg1,
214 GNUNET_NO,
215 &check_addr,
216 &i));
217 GNUNET_assert (i == 0);
218 GNUNET_free (msg1);
219
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
221 "Testing address iteration to copy HELLO...\n");
222 i = 2;
223 msg1 = GNUNET_HELLO_iterate_addresses (msg3,
224 GNUNET_YES,
225 &remove_some,
226 &i);
227 GNUNET_assert (msg1 != NULL);
228 GNUNET_assert (i == 0);
229 i = 1;
230 GNUNET_assert (NULL ==
231 GNUNET_HELLO_iterate_addresses (msg1,
232 GNUNET_NO,
233 &check_addr,
234 &i));
235 GNUNET_assert (i == 0);
236 GNUNET_free (msg1);
237
238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
239 "Testing delta address iteration...\n");
240 i = 2;
241 GNUNET_HELLO_iterate_new_addresses (msg3,
242 msg2,
243 startup_time,
244 &check_addr,
245 &i);
246 GNUNET_assert (i == 0);
247 GNUNET_free (msg2);
248 GNUNET_free (msg3);
249 return 0; /* testcase passed */
250}
251
252
253/* end of test_hello.c */