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.c898
-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, 3518 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 dd191738f..000000000
--- a/src/hello/hello-uri.c
+++ /dev/null
@@ -1,898 +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_log (GNUNET_ERROR_TYPE_DEBUG,
226 "Hashing over %.*s\n",
227 (int) a->uri_len,
228 a->uri);
229 GNUNET_CRYPTO_hash_context_read (hc,
230 a->uri,
231 a->uri_len);
232 }
233 GNUNET_CRYPTO_hash_context_finish (hc,
234 hash);
235
236}
237
238
239/**
240 * Create HELLO signature.
241 *
242 * @param builder the builder to use
243 * @param et expiration time to sign
244 * @param priv key to sign with
245 * @param[out] sig where to write the signature
246 */
247static void
248sign_hello (const struct GNUNET_HELLO_Builder *builder,
249 struct GNUNET_TIME_Timestamp et,
250 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
251 struct GNUNET_CRYPTO_EddsaSignature *sig)
252{
253 struct HelloSignaturePurpose hsp = {
254 .purpose.size = htonl (sizeof (hsp)),
255 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
256 .expiration_time = GNUNET_TIME_absolute_hton (et.abs_time)
257 };
258
259 hash_addresses (builder,
260 &hsp.h_addrs);
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 "Address hash is %s\n",
263 GNUNET_h2s_full (&hsp.h_addrs));
264 GNUNET_CRYPTO_eddsa_sign (priv,
265 &hsp,
266 sig);
267}
268
269
270/**
271 * Verify HELLO signature.
272 *
273 * @param builder the builder to use
274 * @param et expiration time to verify
275 * @param sig signature to verify
276 * @return #GNUNET_OK if everything is ok, #GNUNET_NO if the
277 * HELLO expired, #GNUNET_SYSERR if the signature is wrong
278 */
279static enum GNUNET_GenericReturnValue
280verify_hello (const struct GNUNET_HELLO_Builder *builder,
281 struct GNUNET_TIME_Absolute et,
282 const struct GNUNET_CRYPTO_EddsaSignature *sig)
283{
284 struct HelloSignaturePurpose hsp = {
285 .purpose.size = htonl (sizeof (hsp)),
286 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
287 .expiration_time = GNUNET_TIME_absolute_hton (et)
288 };
289
290 hash_addresses (builder,
291 &hsp.h_addrs);
292 if (GNUNET_OK !=
293 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_HELLO,
294 &hsp,
295 sig,
296 &builder->pid.public_key))
297 {
298 GNUNET_break_op (0);
299 return GNUNET_SYSERR;
300 }
301 if (GNUNET_TIME_absolute_is_past (et))
302 return GNUNET_NO;
303 return GNUNET_OK;
304}
305
306
307struct GNUNET_HELLO_Builder *
308GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid)
309{
310 struct GNUNET_HELLO_Builder *builder;
311
312 builder = GNUNET_new (struct GNUNET_HELLO_Builder);
313 builder->pid = *pid;
314 return builder;
315}
316
317
318void
319GNUNET_HELLO_builder_free (struct GNUNET_HELLO_Builder *builder)
320{
321 struct Address *a;
322
323 while (NULL != (a = builder->a_head))
324 {
325 GNUNET_CONTAINER_DLL_remove (builder->a_head,
326 builder->a_tail,
327 a);
328 builder->a_length--;
329 GNUNET_free (a);
330 }
331 GNUNET_assert (0 == builder->a_length);
332 GNUNET_free (builder);
333}
334
335
336struct GNUNET_HELLO_Builder *
337GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg)
338{
339 const struct HelloUriMessage *h;
340 uint16_t size = ntohs (msg->size);
341
342 if (GNUNET_MESSAGE_TYPE_HELLO_URI != ntohs (msg->type))
343 {
344 GNUNET_break (0);
345 return NULL;
346 }
347 if (sizeof (struct HelloUriMessage) > size)
348 {
349 GNUNET_break_op (0);
350 return NULL;
351 }
352 h = (const struct HelloUriMessage *) msg;
353 size -= sizeof (*h);
354 return GNUNET_HELLO_builder_from_block (&h[1],
355 size);
356}
357
358
359struct GNUNET_HELLO_Builder *
360GNUNET_HELLO_builder_from_block (const void *block,
361 size_t block_size)
362{
363 const struct BlockHeader *bh = block;
364 struct GNUNET_HELLO_Builder *b;
365
366 if (block_size < sizeof (*bh))
367 {
368 GNUNET_break_op (0);
369 return NULL;
370 }
371 b = GNUNET_HELLO_builder_new (&bh->pid);
372 block += sizeof (*bh);
373 block_size -= sizeof (*bh);
374 while (block_size > 0)
375 {
376 const void *end = memchr (block,
377 '\0',
378 block_size);
379
380 if (NULL == end)
381 {
382 GNUNET_break_op (0);
383 GNUNET_HELLO_builder_free (b);
384 return NULL;
385 }
386 if (GNUNET_OK !=
387 GNUNET_HELLO_builder_add_address (b,
388 block))
389 {
390 GNUNET_break_op (0);
391 GNUNET_HELLO_builder_free (b);
392 return NULL;
393 }
394 end++;
395 block_size -= (end - block);
396 block = end;
397 }
398 {
399 enum GNUNET_GenericReturnValue ret;
400
401 ret = verify_hello (b,
402 GNUNET_TIME_absolute_ntoh (bh->expiration_time),
403 &bh->sig);
404 GNUNET_break (GNUNET_SYSERR != ret);
405 if (GNUNET_OK != ret)
406 {
407 GNUNET_HELLO_builder_free (b);
408 return NULL;
409 }
410 }
411 return b;
412}
413
414
415struct GNUNET_HELLO_Builder *
416GNUNET_HELLO_builder_from_url (const char *url)
417{
418 const char *q;
419 const char *s1;
420 const char *s2;
421 struct GNUNET_PeerIdentity pid;
422 struct GNUNET_CRYPTO_EddsaSignature sig;
423 struct GNUNET_TIME_Absolute et;
424 size_t len;
425 struct GNUNET_HELLO_Builder *b;
426
427 if (0 != strncasecmp (url,
428 "gnunet://hello/",
429 strlen ("gnunet://hello/")))
430 return NULL;
431 url += strlen ("gnunet://hello/");
432 s1 = strchr (url, '/');
433 if (NULL == s1)
434 {
435 GNUNET_break_op (0);
436 return NULL;
437 }
438 s2 = strchr (s1 + 1, '/');
439 if (NULL == s1)
440 {
441 GNUNET_break_op (0);
442 return NULL;
443 }
444 q = strchr (url, '?');
445 if (NULL == q)
446 q = url + strlen (url);
447 if (GNUNET_OK !=
448 GNUNET_STRINGS_string_to_data (url,
449 s1 - url,
450 &pid,
451 sizeof(pid)))
452 {
453 GNUNET_break_op (0);
454 return NULL;
455 }
456 if (GNUNET_OK !=
457 GNUNET_STRINGS_string_to_data (s1 + 1,
458 s2 - (s1 + 1),
459 &sig,
460 sizeof(sig)))
461 {
462 GNUNET_break_op (0);
463 return NULL;
464 }
465 {
466 unsigned long long sec;
467 char dummy = '?';
468
469 if ( (0 == sscanf (s2 + 1,
470 "%llu%c",
471 &sec,
472 &dummy)) ||
473 ('?' != dummy) )
474 {
475 GNUNET_break_op (0);
476 return NULL;
477 }
478 et = GNUNET_TIME_absolute_from_s (sec);
479 }
480
481 b = GNUNET_HELLO_builder_new (&pid);
482 len = strlen (q);
483 while (len > 0)
484 {
485 const char *eq;
486 const char *amp;
487 char *addr = NULL;
488 char *uri;
489
490 /* skip ?/& separator */
491 len--;
492 q++;
493 eq = strchr (q, '=');
494 if ( (eq == q) ||
495 (NULL == eq) )
496 {
497 GNUNET_break_op (0);
498 GNUNET_HELLO_builder_free (b);
499 return NULL;
500 }
501 amp = strchr (eq, '&');
502 if (NULL == amp)
503 amp = &q[len];
504 GNUNET_STRINGS_urldecode (eq + 1,
505 amp - (eq + 1),
506 &addr);
507 if ( (NULL == addr) ||
508 (0 == strlen (addr)) )
509 {
510 GNUNET_free (addr);
511 GNUNET_break_op (0);
512 GNUNET_HELLO_builder_free (b);
513 return NULL;
514 }
515 GNUNET_asprintf (&uri,
516 "%.*s://%s",
517 (int) (eq - q),
518 q,
519 addr);
520 GNUNET_free (addr);
521 if (GNUNET_OK !=
522 GNUNET_HELLO_builder_add_address (b,
523 uri))
524 {
525 GNUNET_break_op (0);
526 GNUNET_free (uri);
527 GNUNET_HELLO_builder_free (b);
528 return NULL;
529 }
530 GNUNET_free (uri);
531 /* move to next URL */
532 len -= (amp - q);
533 q = amp;
534 }
535
536 {
537 enum GNUNET_GenericReturnValue ret;
538
539 ret = verify_hello (b,
540 et,
541 &sig);
542 GNUNET_break (GNUNET_SYSERR != ret);
543 if (GNUNET_OK != ret)
544 {
545 GNUNET_HELLO_builder_free (b);
546 return NULL;
547 }
548 }
549 return b;
550}
551
552
553struct GNUNET_MQ_Envelope *
554GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder,
555 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
556{
557 struct GNUNET_MQ_Envelope *env;
558 struct HelloUriMessage *msg;
559 size_t blen;
560
561 if (builder->a_length > UINT16_MAX)
562 {
563 GNUNET_break (0);
564 return NULL;
565 }
566 blen = 0;
567 GNUNET_assert (GNUNET_NO ==
568 GNUNET_HELLO_builder_to_block (builder,
569 priv,
570 NULL,
571 &blen));
572 env = GNUNET_MQ_msg_extra (msg,
573 blen,
574 GNUNET_MESSAGE_TYPE_HELLO_URI);
575 msg->url_counter = htons ((uint16_t) builder->a_length);
576 GNUNET_assert (GNUNET_OK ==
577 GNUNET_HELLO_builder_to_block (builder,
578 priv,
579 &msg[1],
580 &blen));
581 return env;
582}
583
584
585struct GNUNET_MessageHeader *
586GNUNET_HELLO_builder_to_dht_hello_msg (
587 const struct GNUNET_HELLO_Builder *builder,
588 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
589{
590 struct DhtHelloMessage *msg;
591 size_t blen;
592
593 if (builder->a_length > UINT16_MAX)
594 {
595 GNUNET_break (0);
596 return NULL;
597 }
598 blen = 0;
599 GNUNET_assert (GNUNET_NO ==
600 GNUNET_HELLO_builder_to_block (builder,
601 priv,
602 NULL,
603 &blen));
604 GNUNET_assert (blen < UINT16_MAX);
605 GNUNET_assert (blen >= sizeof (struct BlockHeader));
606 {
607 char buf[blen] GNUNET_ALIGN;
608 const struct BlockHeader *block = (const struct BlockHeader *) buf;
609
610 GNUNET_assert (GNUNET_OK ==
611 GNUNET_HELLO_builder_to_block (builder,
612 priv,
613 buf,
614 &blen));
615 msg = GNUNET_malloc (sizeof (*msg)
616 + blen
617 - sizeof (*block));
618 msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO);
619 msg->header.size = htons (sizeof (*msg)
620 + blen
621 - sizeof (*block));
622 memcpy (&msg[1],
623 &block[1],
624 blen - sizeof (*block));
625 msg->sig = block->sig;
626 msg->expiration_time = block->expiration_time;
627 }
628 msg->url_counter = htons ((uint16_t) builder->a_length);
629 return &msg->header;
630}
631
632
633char *
634GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
635 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
636{
637 struct GNUNET_CRYPTO_EddsaSignature sig;
638 struct GNUNET_TIME_Timestamp et;
639 char *result;
640 char *pids;
641 char *sigs;
642 const char *sep = "?";
643
644 et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
645 sign_hello (builder,
646 et,
647 priv,
648 &sig);
649 pids = GNUNET_STRINGS_data_to_string_alloc (&builder->pid,
650 sizeof (builder->pid));
651 sigs = GNUNET_STRINGS_data_to_string_alloc (&sig,
652 sizeof (sig));
653 GNUNET_asprintf (&result,
654 "gnunet://hello/%s/%s/%llu",
655 pids,
656 sigs,
657 (unsigned long long) GNUNET_TIME_timestamp_to_s (et));
658 GNUNET_free (sigs);
659 GNUNET_free (pids);
660 for (struct Address *a = builder->a_head;
661 NULL != a;
662 a = a->next)
663 {
664 char *ue;
665 char *tmp;
666 int pfx_len;
667 const char *eou;
668
669 eou = strstr (a->uri,
670 "://");
671 if (NULL == eou)
672 {
673 GNUNET_break (0);
674 GNUNET_free (result);
675 return NULL;
676 }
677 pfx_len = eou - a->uri;
678 eou += 3;
679 GNUNET_STRINGS_urlencode (eou,
680 a->uri_len - 4 - pfx_len,
681 &ue);
682 GNUNET_asprintf (&tmp,
683 "%s%s%.*s=%s",
684 result,
685 sep,
686 pfx_len,
687 a->uri,
688 ue);
689 GNUNET_free (ue);
690 GNUNET_free (result);
691 result = tmp;
692 sep = "&";
693 }
694 return result;
695}
696
697
698enum GNUNET_GenericReturnValue
699GNUNET_HELLO_builder_to_block (const struct GNUNET_HELLO_Builder *builder,
700 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
701 void *block,
702 size_t *block_size)
703{
704 struct BlockHeader bh;
705 size_t needed = sizeof (bh);
706 char *pos;
707 struct GNUNET_TIME_Timestamp et;
708
709 for (struct Address *a = builder->a_head;
710 NULL != a;
711 a = a->next)
712 {
713 GNUNET_assert (needed + a->uri_len > needed);
714 needed += a->uri_len;
715 }
716 if ( (NULL == block) ||
717 (needed < *block_size) )
718 {
719 *block_size = needed;
720 return GNUNET_NO;
721 }
722 bh.pid = builder->pid;
723 et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
724 bh.expiration_time = GNUNET_TIME_absolute_hton (et.abs_time);
725 sign_hello (builder,
726 et,
727 priv,
728 &bh.sig);
729 memcpy (block,
730 &bh,
731 sizeof (bh));
732 pos = block + sizeof (bh);
733 for (struct Address *a = builder->a_head;
734 NULL != a;
735 a = a->next)
736 {
737 memcpy (pos,
738 a->uri,
739 a->uri_len);
740 pos += a->uri_len;
741 }
742 *block_size = needed;
743 return GNUNET_OK;
744}
745
746
747enum GNUNET_GenericReturnValue
748GNUNET_HELLO_builder_add_address (struct GNUNET_HELLO_Builder *builder,
749 const char *address)
750{
751 size_t alen = strlen (address) + 1;
752 struct Address *a;
753 const char *e;
754
755 if (NULL == (e = strstr (address,
756 "://")))
757 {
758 GNUNET_break_op (0);
759 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
760 "Invalid address `%s'\n",
761 address);
762 return GNUNET_SYSERR;
763 }
764 if (e == address)
765 {
766 GNUNET_break_op (0);
767 return GNUNET_SYSERR;
768 }
769 for (const char *p = address; p != e; p++)
770 if ( (! isalpha ((unsigned char) *p)) &&
771 ('+' != *p) )
772 {
773 GNUNET_break_op (0);
774 return GNUNET_SYSERR;
775 }
776 /* check for duplicates */
777 for (a = builder->a_head;
778 NULL != a;
779 a = a->next)
780 if (0 == strcmp (address,
781 a->uri))
782 return GNUNET_NO;
783 a = GNUNET_malloc (sizeof (struct Address) + alen);
784 a->uri_len = alen;
785 memcpy (&a[1],
786 address,
787 alen);
788 a->uri = (const char *) &a[1];
789 GNUNET_CONTAINER_DLL_insert_tail (builder->a_head,
790 builder->a_tail,
791 a);
792 builder->a_length++;
793 return GNUNET_OK;
794}
795
796
797enum GNUNET_GenericReturnValue
798GNUNET_HELLO_builder_del_address (struct GNUNET_HELLO_Builder *builder,
799 const char *address)
800{
801 struct Address *a;
802
803 /* check for duplicates */
804 for (a = builder->a_head;
805 NULL != a;
806 a = a->next)
807 if (0 == strcmp (address,
808 a->uri))
809 break;
810 if (NULL == a)
811 return GNUNET_NO;
812 GNUNET_CONTAINER_DLL_remove (builder->a_head,
813 builder->a_tail,
814 a);
815 builder->a_length--;
816 GNUNET_free (a);
817 return GNUNET_OK;
818}
819
820
821void
822GNUNET_HELLO_builder_iterate (const struct GNUNET_HELLO_Builder *builder,
823 struct GNUNET_PeerIdentity *pid,
824 GNUNET_HELLO_UriCallback uc,
825 void *uc_cls)
826{
827 struct Address *nxt;
828
829 *pid = builder->pid;
830 if (NULL == uc)
831 return;
832 for (struct Address *a = builder->a_head;
833 NULL != a;
834 a = nxt)
835 {
836 nxt = a->next;
837 uc (uc_cls,
838 a->uri);
839 }
840}
841
842
843enum GNUNET_GenericReturnValue
844GNUNET_HELLO_dht_msg_to_block (const struct GNUNET_MessageHeader *hello,
845 const struct GNUNET_PeerIdentity *pid,
846 void **block,
847 size_t *block_size,
848 struct GNUNET_TIME_Absolute *block_expiration)
849{
850 const struct DhtHelloMessage *msg
851 = (const struct DhtHelloMessage *) hello;
852 uint16_t len = ntohs (hello->size);
853 struct BlockHeader *bh;
854 struct GNUNET_HELLO_Builder *b;
855 enum GNUNET_GenericReturnValue ret;
856
857 if (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO != ntohs (hello->type))
858 {
859 GNUNET_break (0);
860 return GNUNET_SYSERR;
861 }
862 if (len < sizeof (*msg))
863 {
864 GNUNET_break_op (0);
865 return GNUNET_SYSERR;
866 }
867 len -= sizeof (*msg);
868 *block_size = len + sizeof (*bh);
869 *block = GNUNET_malloc (*block_size);
870 bh = *block;
871 bh->pid = *pid;
872 bh->sig = msg->sig;
873 bh->expiration_time = msg->expiration_time;
874 *block_expiration = GNUNET_TIME_absolute_ntoh (msg->expiration_time);
875 memcpy (&bh[1],
876 &msg[1],
877 len);
878 b = GNUNET_HELLO_builder_from_block (*block,
879 *block_size);
880 if (NULL == b)
881 {
882 GNUNET_break_op (0);
883 GNUNET_free (*block);
884 *block_size = 0;
885 return GNUNET_SYSERR;
886 }
887 ret = verify_hello (b,
888 *block_expiration,
889 &msg->sig);
890 GNUNET_HELLO_builder_free (b);
891 if (GNUNET_SYSERR == ret)
892 {
893 GNUNET_free (*block);
894 *block_size = 0;
895 return GNUNET_SYSERR;
896 }
897 return ret;
898}
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 */