aboutsummaryrefslogtreecommitdiff
path: root/src/cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/.gitignore2
-rw-r--r--src/cli/Makefile.am21
-rw-r--r--src/cli/arm/.gitignore1
-rw-r--r--src/cli/arm/Makefile.am45
-rw-r--r--src/cli/arm/gnunet-arm.c1065
-rw-r--r--src/cli/arm/meson.build8
-rw-r--r--src/cli/cadet/.gitignore1
-rw-r--r--src/cli/cadet/Makefile.am26
-rw-r--r--src/cli/cadet/gnunet-cadet.c851
-rw-r--r--src/cli/cadet/meson.build15
-rw-r--r--src/cli/core/.gitignore1
-rw-r--r--src/cli/core/Makefile.am24
-rw-r--r--src/cli/core/gnunet-core.c274
-rw-r--r--src/cli/core/meson.build6
-rw-r--r--src/cli/datastore/.gitignore1
-rw-r--r--src/cli/datastore/Makefile.am24
-rw-r--r--src/cli/datastore/gnunet-datastore.c508
-rw-r--r--src/cli/datastore/meson.build9
-rw-r--r--src/cli/dht/.gitignore5
-rw-r--r--src/cli/dht/Makefile.am52
-rw-r--r--src/cli/dht/gnunet-dht-get.c352
-rw-r--r--src/cli/dht/gnunet-dht-hello.c178
-rw-r--r--src/cli/dht/gnunet-dht-monitor.c345
-rw-r--r--src/cli/dht/gnunet-dht-put.c255
-rw-r--r--src/cli/dht/meson.build25
-rw-r--r--src/cli/fs/.gitignore8
-rw-r--r--src/cli/fs/Makefile.am107
-rw-r--r--src/cli/fs/gnunet-auto-share.c791
-rw-r--r--src/cli/fs/gnunet-directory.c212
-rw-r--r--src/cli/fs/gnunet-download.c385
-rw-r--r--src/cli/fs/gnunet-fs.c191
-rw-r--r--src/cli/fs/gnunet-publish.c1009
-rw-r--r--src/cli/fs/gnunet-search.c801
-rw-r--r--src/cli/fs/gnunet-unindex.c206
-rw-r--r--src/cli/fs/meson.build51
-rw-r--r--src/cli/gns/.gitignore2
-rw-r--r--src/cli/gns/Makefile.am108
-rw-r--r--src/cli/gns/gnunet-gns-proxy-ca.template303
-rw-r--r--src/cli/gns/gnunet-gns-proxy-setup-ca.in339
-rw-r--r--src/cli/gns/gnunet-gns.c411
-rw-r--r--src/cli/gns/meson.build69
-rw-r--r--src/cli/gns/openssl.cnf244
-rw-r--r--src/cli/gns/test_dns2gns.conf69
-rwxr-xr-xsrc/cli/gns/test_dns2gns.sh52
-rwxr-xr-xsrc/cli/gns/test_gns_at_lookup.sh41
-rwxr-xr-xsrc/cli/gns/test_gns_box_sbox.sh59
-rwxr-xr-xsrc/cli/gns/test_gns_caa_lookup.sh38
-rwxr-xr-xsrc/cli/gns/test_gns_config_lookup.sh44
-rw-r--r--src/cli/gns/test_gns_defaults.conf34
-rwxr-xr-xsrc/cli/gns/test_gns_delegated_lookup.sh45
-rwxr-xr-xsrc/cli/gns/test_gns_dht_lookup.sh63
-rwxr-xr-xsrc/cli/gns/test_gns_gns2dns_cname_lookup.sh98
-rwxr-xr-xsrc/cli/gns/test_gns_gns2dns_lookup.sh117
-rwxr-xr-xsrc/cli/gns/test_gns_gns2dns_zkey_lookup.sh116
-rwxr-xr-xsrc/cli/gns/test_gns_ipv6_lookup.sh37
-rwxr-xr-xsrc/cli/gns/test_gns_lightest.sh141
-rw-r--r--src/cli/gns/test_gns_lookup.conf65
-rwxr-xr-xsrc/cli/gns/test_gns_lookup.sh37
-rw-r--r--src/cli/gns/test_gns_lookup_peer1.conf75
-rw-r--r--src/cli/gns/test_gns_lookup_peer2.conf72
-rwxr-xr-xsrc/cli/gns/test_gns_multiple_record_lookup.sh95
-rwxr-xr-xsrc/cli/gns/test_gns_mx_lookup.sh44
-rwxr-xr-xsrc/cli/gns/test_gns_quickupdate.sh65
-rwxr-xr-xsrc/cli/gns/test_gns_redirect_lookup.sh100
-rwxr-xr-xsrc/cli/gns/test_gns_rel_expiration.sh64
-rwxr-xr-xsrc/cli/gns/test_gns_revocation.sh50
-rwxr-xr-xsrc/cli/gns/test_gns_sbox.sh121
-rwxr-xr-xsrc/cli/gns/test_gns_sbox_simple.sh39
-rw-r--r--src/cli/gns/test_gns_simple_lookup.conf97
-rwxr-xr-xsrc/cli/gns/test_gns_soa_lookup.sh51
-rwxr-xr-xsrc/cli/gns/test_gns_txt_lookup.sh38
-rwxr-xr-xsrc/cli/gns/test_gns_zkey_lookup.sh39
-rwxr-xr-xsrc/cli/gns/test_gnunet_gns.sh.in47
-rw-r--r--src/cli/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkeybin0 -> 827 bytes
-rw-r--r--src/cli/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkeybin0 -> 826 bytes
-rw-r--r--src/cli/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkeybin0 -> 826 bytes
-rw-r--r--src/cli/gns/zonefiles/test_zonekeybin0 -> 827 bytes
-rw-r--r--src/cli/identity/.gitignore1
-rw-r--r--src/cli/identity/Makefile.am35
-rw-r--r--src/cli/identity/gnunet-identity.c624
-rw-r--r--src/cli/identity/meson.build9
-rwxr-xr-xsrc/cli/identity/test_identity_messages.sh50
-rw-r--r--src/cli/meson.build20
-rw-r--r--src/cli/messenger/.gitignore1
-rw-r--r--src/cli/messenger/Makefile.am25
-rw-r--r--src/cli/messenger/gnunet-messenger.c415
-rw-r--r--src/cli/messenger/meson.build9
-rw-r--r--src/cli/namecache/.gitignore1
-rw-r--r--src/cli/namecache/Makefile.am20
-rw-r--r--src/cli/namecache/gnunet-namecache.c245
-rw-r--r--src/cli/namecache/meson.build10
-rw-r--r--src/cli/namestore/.gitignore6
-rw-r--r--src/cli/namestore/Makefile.am70
-rw-r--r--src/cli/namestore/example_zonefile27
-rw-r--r--src/cli/namestore/gnunet-namestore-dbtool.c199
-rw-r--r--src/cli/namestore/gnunet-namestore-zonefile.c729
-rw-r--r--src/cli/namestore/gnunet-namestore.c2118
-rw-r--r--src/cli/namestore/gnunet-zoneimport.c1882
-rw-r--r--src/cli/namestore/meson.build38
-rwxr-xr-xsrc/cli/namestore/test_namestore_box_lightest.sh63
-rwxr-xr-xsrc/cli/namestore/test_namestore_delete.sh68
-rwxr-xr-xsrc/cli/namestore/test_namestore_lookup.sh63
-rwxr-xr-xsrc/cli/namestore/test_namestore_put.sh55
-rwxr-xr-xsrc/cli/namestore/test_namestore_put_multiple.sh112
-rwxr-xr-xsrc/cli/namestore/test_namestore_put_stdin.sh68
-rwxr-xr-xsrc/cli/namestore/test_namestore_zonefile_import.sh33
-rw-r--r--src/cli/nat-auto/.gitignore2
-rw-r--r--src/cli/nat-auto/Makefile.am26
-rw-r--r--src/cli/nat-auto/gnunet-nat-auto.c367
-rw-r--r--src/cli/nat-auto/gnunet-nat-server.c403
-rw-r--r--src/cli/nat-auto/meson.build14
-rw-r--r--src/cli/nat/.gitignore1
-rw-r--r--src/cli/nat/Makefile.am17
-rw-r--r--src/cli/nat/gnunet-nat.c476
-rw-r--r--src/cli/nat/meson.build7
-rw-r--r--src/cli/nse/.gitignore1
-rw-r--r--src/cli/nse/Makefile.am19
-rw-r--r--src/cli/nse/gnunet-nse.c143
-rw-r--r--src/cli/nse/meson.build7
-rw-r--r--src/cli/peerstore/.gitignore1
-rw-r--r--src/cli/peerstore/Makefile.am23
-rw-r--r--src/cli/peerstore/gnunet-peerstore.c97
-rw-r--r--src/cli/peerstore/meson.build9
-rw-r--r--src/cli/reclaim/.gitignore2
-rw-r--r--src/cli/reclaim/Makefile.am57
-rw-r--r--src/cli/reclaim/gnunet-did.c661
-rw-r--r--src/cli/reclaim/gnunet-reclaim.c943
-rw-r--r--src/cli/reclaim/meson.build22
-rw-r--r--src/cli/reclaim/test_reclaim.conf44
-rwxr-xr-xsrc/cli/reclaim/test_reclaim.sh31
-rwxr-xr-xsrc/cli/reclaim/test_reclaim_attribute.sh40
-rwxr-xr-xsrc/cli/reclaim/test_reclaim_consume.sh51
-rw-r--r--src/cli/reclaim/test_reclaim_defaults.conf24
-rwxr-xr-xsrc/cli/reclaim/test_reclaim_issue.sh42
-rwxr-xr-xsrc/cli/reclaim/test_reclaim_oidc.sh57
-rwxr-xr-xsrc/cli/reclaim/test_reclaim_revoke.sh65
-rw-r--r--src/cli/revocation/Makefile.am52
-rw-r--r--src/cli/revocation/gnunet-revocation-tvg.c230
-rw-r--r--src/cli/revocation/gnunet-revocation.c581
-rw-r--r--src/cli/revocation/meson.build22
-rw-r--r--src/cli/revocation/test_local_revocation.py.in129
-rw-r--r--src/cli/statistics/.gitignore1
-rw-r--r--src/cli/statistics/Makefile.am40
-rw-r--r--src/cli/statistics/gnunet-statistics.c889
-rw-r--r--src/cli/statistics/meson.build8
-rw-r--r--src/cli/util/.gitignore10
-rw-r--r--src/cli/util/Makefile.am108
-rw-r--r--src/cli/util/crypto-test-vectors.json56
-rw-r--r--src/cli/util/gnunet-base32.c155
-rw-r--r--src/cli/util/gnunet-config-diff.c24
-rw-r--r--src/cli/util/gnunet-config.c206
-rw-r--r--src/cli/util/gnunet-crypto-tvg.c1608
-rw-r--r--src/cli/util/gnunet-ecc.c510
-rw-r--r--src/cli/util/gnunet-qr.c597
-rw-r--r--src/cli/util/gnunet-resolver.c191
-rw-r--r--src/cli/util/gnunet-scrypt.c325
-rw-r--r--src/cli/util/gnunet-timeout.c119
-rw-r--r--src/cli/util/gnunet-uri.c192
-rw-r--r--src/cli/util/meson.build62
-rwxr-xr-xsrc/cli/util/test_crypto_vectors.sh3
-rw-r--r--src/cli/vpn/.gitignore1
-rw-r--r--src/cli/vpn/Makefile.am22
-rw-r--r--src/cli/vpn/gnunet-vpn.c364
-rw-r--r--src/cli/vpn/meson.build13
164 files changed, 28550 insertions, 0 deletions
diff --git a/src/cli/.gitignore b/src/cli/.gitignore
new file mode 100644
index 000000000..cedad92f1
--- /dev/null
+++ b/src/cli/.gitignore
@@ -0,0 +1,2 @@
1gnunet-revocation
2gnunet-revocation-tvg
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am
new file mode 100644
index 000000000..6ad6dd70a
--- /dev/null
+++ b/src/cli/Makefile.am
@@ -0,0 +1,21 @@
1SUBDIRS = \
2 util \
3 arm \
4 statistics \
5 peerstore \
6 core \
7 nat \
8 nat-auto \
9 nse \
10 datastore \
11 dht \
12 identity \
13 namecache \
14 namestore \
15 revocation \
16 vpn \
17 gns \
18 fs \
19 cadet \
20 reclaim \
21 messenger
diff --git a/src/cli/arm/.gitignore b/src/cli/arm/.gitignore
new file mode 100644
index 000000000..f010c20a1
--- /dev/null
+++ b/src/cli/arm/.gitignore
@@ -0,0 +1 @@
gnunet-arm
diff --git a/src/cli/arm/Makefile.am b/src/cli/arm/Makefile.am
new file mode 100644
index 000000000..2d41ab141
--- /dev/null
+++ b/src/cli/arm/Makefile.am
@@ -0,0 +1,45 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage -O0
10 XLIB = -lgcov
11endif
12
13bin_PROGRAMS = \
14 gnunet-arm
15
16gnunet_arm_SOURCES = \
17 gnunet-arm.c
18gnunet_arm_LDADD = \
19 $(top_builddir)/src/service/arm/libgnunetarm.la \
20 $(top_builddir)/src/lib/util/libgnunetutil.la \
21 $(GN_LIBINTL)
22
23# FIXME the respective conf file now resides in service/arm/
24#if HAVE_PYTHON
25#check_SCRIPTS = \
26# test_gnunet_arm.py
27#endif
28
29if ENABLE_TEST_RUN
30AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
31TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
32endif
33
34#SUFFIXES = .py.in .py
35#.py.in.py:
36# $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/$< > $@
37# chmod +x $@
38#
39#test_gnunet_arm.py: test_gnunet_arm.py.in Makefile
40# $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/test_gnunet_arm.py.in > test_gnunet_arm.py
41# chmod +x test_gnunet_arm.py
42#
43#EXTRA_DIST = \
44# test_arm_api_data.conf \
45# test_gnunet_arm.py.in
diff --git a/src/cli/arm/gnunet-arm.c b/src/cli/arm/gnunet-arm.c
new file mode 100644
index 000000000..ea3a012ab
--- /dev/null
+++ b/src/cli/arm/gnunet-arm.c
@@ -0,0 +1,1065 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012, 2013 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 arm/gnunet-arm.c
23 * @brief arm for writing a tool
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_arm_service.h"
28#include "gnunet_constants.h"
29#include "gnunet_util_lib.h"
30
31/**
32 * Set if we are to shutdown all services (including ARM).
33 */
34static int end;
35
36/**
37 * Set if we are to start default services (including ARM).
38 */
39static int start;
40
41/**
42 * Set if we are to stop/start default services (including ARM).
43 */
44static int restart;
45
46/**
47 * Set if we should delete configuration and temp directory on exit.
48 */
49static int delete;
50
51/**
52 * Set if we should not print status messages.
53 */
54static int quiet;
55
56/**
57 * Set if we should print all services, including stopped ones.
58 */
59static int show_all;
60
61/**
62 * Monitor ARM activity.
63 */
64static int monitor;
65
66/**
67 * Set if we should print a list of currently running services.
68 */
69static int list;
70
71/**
72 * Set to the name of a service to start.
73 */
74static char *init;
75
76/**
77 * Set to the name of a service to kill.
78 */
79static char *term;
80
81/**
82 * Set to the name of the config file used.
83 */
84static char *config_file;
85
86/**
87 * Set to the directory where runtime files are stored.
88 */
89static char *dir;
90
91/**
92 * Final status code.
93 */
94static int ret;
95
96/**
97 * Connection with ARM.
98 */
99static struct GNUNET_ARM_Handle *h;
100
101/**
102 * Monitor connection with ARM.
103 */
104static struct GNUNET_ARM_MonitorHandle *m;
105
106/**
107 * Our configuration.
108 */
109static struct GNUNET_CONFIGURATION_Handle *cfg;
110
111/**
112 * Processing stage that we are in. Simple counter.
113 */
114static unsigned int phase;
115
116/**
117 * User defined timestamp for completing operations.
118 */
119static struct GNUNET_TIME_Relative timeout;
120
121/**
122 * Task to be run on timeout.
123 */
124static struct GNUNET_SCHEDULER_Task *timeout_task;
125
126/**
127 * Do we want to give our stdout to gnunet-service-arm?
128 */
129static int no_stdout;
130
131/**
132 * Do we want to give our stderr to gnunet-service-arm?
133 */
134static int no_stderr;
135
136/**
137 * Handle for the task running the #action_loop().
138 */
139static struct GNUNET_SCHEDULER_Task *al_task;
140
141/**
142 * Current operation.
143 */
144static struct GNUNET_ARM_Operation *op;
145
146/**
147 * Attempts to delete configuration file and GNUNET_HOME
148 * on ARM shutdown provided the end and delete options
149 * were specified when gnunet-arm was run.
150 */
151static void
152delete_files ()
153{
154 GNUNET_log (
155 GNUNET_ERROR_TYPE_DEBUG,
156 "Will attempt to remove configuration file %s and service directory %s\n",
157 config_file,
158 dir);
159 if (0 != unlink (config_file))
160 {
161 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
162 _ ("Failed to remove configuration file %s\n"),
163 config_file);
164 }
165 if (GNUNET_OK != GNUNET_DISK_directory_remove (dir))
166 {
167 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
168 _ ("Failed to remove servicehome directory %s\n"),
169 dir);
170 }
171}
172
173
174/**
175 * Main continuation-passing-style loop. Runs the various
176 * jobs that we've been asked to do in order.
177 *
178 * @param cls closure, unused
179 */
180static void
181shutdown_task (void *cls)
182{
183 (void) cls;
184 if (NULL != al_task)
185 {
186 GNUNET_SCHEDULER_cancel (al_task);
187 al_task = NULL;
188 }
189 if (NULL != op)
190 {
191 GNUNET_ARM_operation_cancel (op);
192 op = NULL;
193 }
194 if (NULL != h)
195 {
196 GNUNET_ARM_disconnect (h);
197 h = NULL;
198 }
199 if (NULL != m)
200 {
201 GNUNET_ARM_monitor_stop (m);
202 m = NULL;
203 }
204 if (NULL != timeout_task)
205 {
206 GNUNET_SCHEDULER_cancel (timeout_task);
207 timeout_task = NULL;
208 }
209 if ( (GNUNET_YES == end) &&
210 (GNUNET_YES == delete) )
211 delete_files ();
212 GNUNET_CONFIGURATION_destroy (cfg);
213 cfg = NULL;
214}
215
216
217/**
218 * Returns a string interpretation of @a rs
219 *
220 * @param rs the request status from ARM
221 * @return a string interpretation of the request status
222 */
223static const char *
224req_string (enum GNUNET_ARM_RequestStatus rs)
225{
226 switch (rs)
227 {
228 case GNUNET_ARM_REQUEST_SENT_OK:
229 return _ ("Message was sent successfully");
230
231 case GNUNET_ARM_REQUEST_DISCONNECTED:
232 return _ ("We disconnected from ARM before we could send a request");
233 }
234 return _ ("Unknown request status");
235}
236
237
238/**
239 * Returns a string interpretation of the @a result
240 *
241 * @param result the arm result
242 * @return a string interpretation
243 */
244static const char *
245ret_string (enum GNUNET_ARM_Result result)
246{
247 switch (result)
248 {
249 case GNUNET_ARM_RESULT_STOPPED:
250 return _ ("is stopped");
251
252 case GNUNET_ARM_RESULT_STARTING:
253 return _ ("is starting");
254
255 case GNUNET_ARM_RESULT_STOPPING:
256 return _ ("is stopping");
257
258 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
259 return _ ("is starting already");
260
261 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
262 return _ ("is stopping already");
263
264 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
265 return _ ("is started already");
266
267 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
268 return _ ("is stopped already");
269
270 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
271 return _ ("service is not known to ARM");
272
273 case GNUNET_ARM_RESULT_START_FAILED:
274 return _ ("service failed to start");
275
276 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
277 return _ ("service cannot be manipulated because ARM is shutting down");
278 }
279 return _ ("Unknown result code.");
280}
281
282
283/**
284 * Main task that runs our various operations in order.
285 *
286 * @param cls closure
287 */
288static void
289action_loop (void *cls);
290
291
292/**
293 * Function called whenever we connect to or disconnect from ARM.
294 * Termiantes the process if we fail to connect to the service on
295 * our first attempt.
296 *
297 * @param cls closure
298 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
299 * #GNUNET_SYSERR on error.
300 */
301static void
302conn_status (void *cls,
303 int connected)
304{
305 static int once;
306
307 (void) cls;
308 if ( (GNUNET_SYSERR == connected) &&
309 (0 == once) )
310 {
311 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
312 _ ("Fatal error initializing ARM API.\n"));
313 GNUNET_SCHEDULER_shutdown ();
314 return;
315 }
316 once = 1;
317}
318
319
320/**
321 * We have requested ARM to be started, this function
322 * is called with the result of the operation. Informs the
323 * use of the result; on success, we continue with the event
324 * loop, on failure we terminate the process.
325 *
326 * @param cls closure unused
327 * @param rs what happened to our request
328 * @param result if the request was processed, this is the result
329 * according to ARM
330 */
331static void
332start_callback (void *cls,
333 enum GNUNET_ARM_RequestStatus rs,
334 enum GNUNET_ARM_Result result)
335{
336 (void) cls;
337 op = NULL;
338 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
339 {
340 fprintf (stdout,
341 _ ("Failed to start the ARM service: %s\n"),
342 req_string (rs));
343 GNUNET_SCHEDULER_shutdown ();
344 return;
345 }
346 if ((GNUNET_ARM_RESULT_STARTING != result) &&
347 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
348 {
349 fprintf (stdout,
350 _ ("Failed to start the ARM service: %s\n"),
351 ret_string (result));
352 GNUNET_SCHEDULER_shutdown ();
353 return;
354 }
355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
356 "ARM service [re]start successful\n");
357 start = 0;
358 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
359 NULL);
360}
361
362
363/**
364 * We have requested ARM to be stopped, this function
365 * is called with the result of the operation. Informs the
366 * use of the result; on success, we continue with the event
367 * loop, on failure we terminate the process.
368 *
369 * @param cls closure unused
370 * @param rs what happened to our request
371 * @param result if the request was processed, this is the result
372 * according to ARM
373 */
374static void
375stop_callback (void *cls,
376 enum GNUNET_ARM_RequestStatus rs,
377 enum GNUNET_ARM_Result result)
378{
379 char *msg;
380
381 (void) cls;
382 op = NULL;
383 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
384 {
385 GNUNET_asprintf (&msg,
386 "%s",
387 _ (
388 "Failed to send a stop request to the ARM service: %s\n"));
389 fprintf (stdout, msg, req_string (rs));
390 GNUNET_free (msg);
391 GNUNET_SCHEDULER_shutdown ();
392 return;
393 }
394 if ( (GNUNET_ARM_RESULT_STOPPING != result) &&
395 (GNUNET_ARM_RESULT_STOPPED != result) &&
396 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result) )
397 {
398 fprintf (stdout,
399 _ ("Failed to stop the ARM service: %s\n"),
400 ret_string (result));
401 GNUNET_SCHEDULER_shutdown ();
402 return;
403 }
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405 "ARM service shutdown successful\n");
406 end = 0;
407 if (restart)
408 {
409 restart = 0;
410 start = 1;
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Initiating an ARM restart\n");
413 }
414 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
415 NULL);
416}
417
418
419/**
420 * We have requested a service to be started, this function
421 * is called with the result of the operation. Informs the
422 * use of the result; on success, we continue with the event
423 * loop, on failure we terminate the process.
424 *
425 * @param cls closure unused
426 * @param rs what happened to our request
427 * @param result if the request was processed, this is the result
428 * according to ARM
429 */
430static void
431init_callback (void *cls,
432 enum GNUNET_ARM_RequestStatus rs,
433 enum GNUNET_ARM_Result result)
434{
435 (void) cls;
436 op = NULL;
437 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
438 {
439 fprintf (stdout,
440 _ ("Failed to send a request to start the `%s' service: %s\n"),
441 init,
442 req_string (rs));
443 GNUNET_SCHEDULER_shutdown ();
444 return;
445 }
446 if ((GNUNET_ARM_RESULT_STARTING != result) &&
447 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
448 {
449 fprintf (stdout,
450 _ ("Failed to start the `%s' service: %s\n"),
451 init,
452 ret_string (result));
453 GNUNET_SCHEDULER_shutdown ();
454 return;
455 }
456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457 "Service %s [re]started successfully\n",
458 init);
459 GNUNET_free (init);
460 init = NULL;
461 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
462 NULL);
463}
464
465
466/**
467 * We have requested a service to be stopped, this function
468 * is called with the result of the operation. Informs the
469 * use of the result; on success, we continue with the event
470 * loop, on failure we terminate the process.
471 *
472 * @param cls closure unused
473 * @param rs what happened to our request
474 * @param result if the request was processed, this is the result
475 * according to ARM
476 */
477static void
478term_callback (void *cls,
479 enum GNUNET_ARM_RequestStatus rs,
480 enum GNUNET_ARM_Result result)
481{
482 char *msg;
483
484 (void) cls;
485 op = NULL;
486 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
487 {
488 GNUNET_asprintf (&msg,
489 _ (
490 "Failed to send a request to kill the `%s' service: %%s\n"),
491 term);
492 fprintf (stdout,
493 msg,
494 req_string (rs));
495 GNUNET_free (msg);
496 GNUNET_SCHEDULER_shutdown ();
497 return;
498 }
499 if ( (GNUNET_ARM_RESULT_STOPPED != result) &&
500 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result) )
501 {
502 fprintf (stdout,
503 _ ("Failed to kill the `%s' service: %s\n"),
504 term,
505 ret_string (result));
506 GNUNET_SCHEDULER_shutdown ();
507 return;
508 }
509
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511 "Service %s stopped successfully\n",
512 term);
513 GNUNET_free (term);
514 term = NULL;
515 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
516 NULL);
517}
518
519
520/**
521 * Function called with the list of running services. Prints
522 * the list to stdout, then starts the event loop again.
523 * Prints an error message and terminates the process on errors.
524 *
525 * @param cls closure (unused)
526 * @param rs request status (success, failure, etc.)
527 * @param count number of services in the list
528 * @param list list of services managed by arm
529 */
530static void
531list_callback (void *cls,
532 enum GNUNET_ARM_RequestStatus rs,
533 unsigned int count,
534 const struct GNUNET_ARM_ServiceInfo *list)
535{
536 unsigned int num_stopped = 0;
537 unsigned int num_started = 0;
538 unsigned int num_stopping = 0;
539 unsigned int num_failed = 0;
540 unsigned int num_finished = 0;
541 (void) cls;
542 op = NULL;
543 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
544 {
545 char *msg;
546
547 GNUNET_asprintf (&msg,
548 "%s",
549 _ ("Failed to request a list of services: %s\n"));
550 fprintf (stdout,
551 msg,
552 req_string (rs));
553 GNUNET_free (msg);
554 ret = 3;
555 GNUNET_SCHEDULER_shutdown ();
556 }
557 if (NULL == list)
558 {
559 fprintf (stderr,
560 "%s",
561 _ ("Error communicating with ARM. ARM not running?\n"));
562 GNUNET_SCHEDULER_shutdown ();
563 ret = 3;
564 return;
565 }
566 for (unsigned int i = 0; i < count; i++)
567 {
568 switch (list[i].status)
569 {
570 case GNUNET_ARM_SERVICE_STATUS_STOPPED:
571 num_stopped++;
572 break;
573 case GNUNET_ARM_SERVICE_STATUS_FAILED:
574 num_failed++;
575 break;
576 case GNUNET_ARM_SERVICE_STATUS_FINISHED:
577 num_finished++;
578 break;
579 case GNUNET_ARM_SERVICE_STATUS_STARTED:
580 num_started++;
581 break;
582 case GNUNET_ARM_SERVICE_STATUS_STOPPING:
583 num_stopping++;
584 fprintf (stdout,
585 "%s (binary='%s', status=stopping)\n",
586 list[i].name,
587 list[i].binary);
588 break;
589 default:
590 GNUNET_break_op (0);
591 fprintf (stdout,
592 "%s (binary='%s', status=unknown)\n",
593 list[i].name,
594 list[i].binary);
595 break;
596 }
597 }
598 if (! quiet)
599 {
600 if (show_all)
601 fprintf (stdout,
602 "%s",
603 _ ("All services:\n"));
604 else
605 fprintf (stdout,
606 "%s",
607 _ ("Services (excluding stopped services):\n"));
608 if (num_stopped || num_failed || num_finished || num_stopping ||
609 num_started)
610 {
611 int sep = 0;
612 fprintf (stdout, "(");
613 if (0 != num_started)
614 {
615 if (sep)
616 fprintf (stdout, " / ");
617 fprintf (stdout,
618 "started: %u",
619 num_started);
620 sep = 1;
621 }
622 if (0 != num_failed)
623 {
624 if (sep)
625 fprintf (stdout, " / ");
626 fprintf (stdout,
627 "failed: %u",
628 num_failed);
629 sep = 1;
630 }
631 if (0 != num_stopping)
632 {
633 if (sep)
634 fprintf (stdout, " / ");
635 fprintf (stdout,
636 "stopping: %u",
637 num_stopping);
638 sep = 1;
639 }
640 if (0 != num_stopped)
641 {
642 if (sep)
643 fprintf (stdout, " / ");
644 fprintf (stdout,
645 "stopped: %u",
646 num_stopped);
647 sep = 1;
648 }
649 if (0 != num_finished)
650 {
651 if (sep)
652 fprintf (stdout, " / ");
653 fprintf (stdout,
654 "finished: %u",
655 num_finished);
656 sep = 1;
657 }
658 fprintf (stdout, ")\n");
659 }
660 else
661 {
662 fprintf (stdout,
663 "%s",
664 _ ("(No services configured.)\n"));
665 }
666 }
667 for (unsigned int i = 0; i < count; i++)
668 {
669 struct GNUNET_TIME_Relative restart_in;
670 switch (list[i].status)
671 {
672 case GNUNET_ARM_SERVICE_STATUS_STOPPED:
673 if (show_all)
674 fprintf (stdout,
675 "%s (binary='%s', status=stopped)\n",
676 list[i].name,
677 list[i].binary);
678 break;
679 case GNUNET_ARM_SERVICE_STATUS_FAILED:
680 restart_in = GNUNET_TIME_absolute_get_remaining (list[i].restart_at);
681 fprintf (stdout,
682 "%s (binary='%s', status=failed, exit_status=%d, restart_delay='%s')\n",
683 list[i].name,
684 list[i].binary,
685 list[i].last_exit_status,
686 GNUNET_STRINGS_relative_time_to_string (restart_in,
687 GNUNET_YES));
688 break;
689 case GNUNET_ARM_SERVICE_STATUS_FINISHED:
690 fprintf (stdout,
691 "%s (binary='%s', status=finished)\n",
692 list[i].name,
693 list[i].binary);
694 break;
695 case GNUNET_ARM_SERVICE_STATUS_STARTED:
696 fprintf (stdout,
697 "%s (binary='%s', status=started)\n",
698 list[i].name,
699 list[i].binary);
700 break;
701 case GNUNET_ARM_SERVICE_STATUS_STOPPING:
702 fprintf (stdout,
703 "%s (binary='%s', status=stopping)\n",
704 list[i].name,
705 list[i].binary);
706 break;
707 default:
708 GNUNET_break_op (0);
709 fprintf (stdout,
710 "%s (binary='%s', status=unknown)\n",
711 list[i].name,
712 list[i].binary);
713 break;
714 }
715 }
716 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
717 NULL);
718}
719
720
721/**
722 * Main action loop. Runs the various jobs that we've been asked to
723 * do, in order.
724 *
725 * @param cls closure, unused
726 */
727static void
728action_loop (void *cls)
729{
730 (void) cls;
731 al_task = NULL;
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
733 "Running requested actions\n");
734 while (1)
735 {
736 switch (phase++)
737 {
738 case 0:
739 if (NULL != term)
740 {
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
742 "Termination action\n");
743 op = GNUNET_ARM_request_service_stop (h,
744 term,
745 &term_callback,
746 NULL);
747 return;
748 }
749 break;
750
751 case 1:
752 if (end || restart)
753 {
754 if (GNUNET_YES !=
755 GNUNET_CLIENT_test (cfg,
756 "arm"))
757 {
758 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
759 "GNUnet not running, cannot stop the peer\n");
760 }
761 else
762 {
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764 "End action\n");
765 op = GNUNET_ARM_request_service_stop (h,
766 "arm",
767 &stop_callback,
768 NULL);
769 return;
770 }
771 }
772 break;
773
774 case 2:
775 if (start)
776 {
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778 "Start action\n");
779 op =
780 GNUNET_ARM_request_service_start (h,
781 "arm",
782 (no_stdout
783 ? 0
784 : GNUNET_OS_INHERIT_STD_OUT)
785 | (no_stderr
786 ? 0
787 : GNUNET_OS_INHERIT_STD_ERR),
788 &start_callback,
789 NULL);
790 return;
791 }
792 break;
793
794 case 3:
795 if (NULL != init)
796 {
797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798 "Initialization action\n");
799 op = GNUNET_ARM_request_service_start (h,
800 init,
801 GNUNET_OS_INHERIT_STD_NONE,
802 &init_callback,
803 NULL);
804 return;
805 }
806 break;
807
808 case 4:
809 if (list)
810 {
811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
812 "Going to list all running services controlled by ARM.\n");
813 op = GNUNET_ARM_request_service_list (h,
814 &list_callback,
815 &list);
816 return;
817 }
818 break;
819
820 case 5:
821 if (monitor)
822 {
823 if (! quiet)
824 fprintf (stderr,
825 _ ("Now only monitoring, press CTRL-C to stop.\n"));
826 quiet =
827 0; /* does not make sense to stay quiet in monitor mode at this time */
828 return; /* done with tasks, just monitor */
829 }
830 break;
831
832 default: /* last phase */
833 GNUNET_SCHEDULER_shutdown ();
834 return;
835 }
836 }
837}
838
839
840/**
841 * Function called when a service starts or stops.
842 *
843 * @param cls closure
844 * @param service service name
845 * @param status status of the service
846 */
847static void
848srv_status (void *cls,
849 const char *service,
850 enum GNUNET_ARM_ServiceMonitorStatus status)
851{
852 const char *msg;
853
854 (void) cls;
855 switch (status)
856 {
857 case GNUNET_ARM_SERVICE_MONITORING_STARTED:
858 return; /* this should be done silently */
859
860 case GNUNET_ARM_SERVICE_STOPPED:
861 msg = _ ("Stopped %s.\n");
862 break;
863
864 case GNUNET_ARM_SERVICE_STARTING:
865 msg = _ ("Starting %s...\n");
866 break;
867
868 case GNUNET_ARM_SERVICE_STOPPING:
869 msg = _ ("Stopping %s...\n");
870 break;
871
872 default:
873 msg = NULL;
874 break;
875 }
876 if (! quiet)
877 {
878 if (NULL != msg)
879 fprintf (stderr,
880 msg,
881 service);
882 else
883 fprintf (stderr,
884 _ ("Unknown status %u for service %s.\n"),
885 status,
886 service);
887 }
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
889 "Got service %s status %d\n",
890 service,
891 (int) status);
892}
893
894
895/**
896 * Task run on timeout (if -T is given).
897 */
898static void
899timeout_task_cb (void *cls)
900{
901 (void) cls;
902 timeout_task = NULL;
903 ret = 2;
904 GNUNET_SCHEDULER_shutdown ();
905}
906
907
908/**
909 * Main function that will be run by the scheduler.
910 *
911 * @param cls closure
912 * @param args remaining command-line arguments
913 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
914 * @param c configuration
915 */
916static void
917run (void *cls,
918 char *const *args,
919 const char *cfgfile,
920 const struct GNUNET_CONFIGURATION_Handle *c)
921{
922 (void) cls;
923 (void) args;
924 (void) cfgfile;
925 cfg = GNUNET_CONFIGURATION_dup (c);
926 if (GNUNET_OK !=
927 GNUNET_CONFIGURATION_get_value_string (cfg,
928 "PATHS",
929 "GNUNET_HOME",
930 &dir))
931 {
932 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
933 "PATHS",
934 "GNUNET_HOME");
935 return;
936 }
937 (void) GNUNET_CONFIGURATION_get_value_filename (cfg,
938 "arm",
939 "CONFIG",
940 &config_file);
941 if (NULL == (h = GNUNET_ARM_connect (cfg,
942 &conn_status,
943 NULL)))
944 return;
945 if (monitor)
946 m = GNUNET_ARM_monitor_start (cfg,
947 &srv_status,
948 NULL);
949 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
950 NULL);
951 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
952 NULL);
953 if (0 != timeout.rel_value_us)
954 timeout_task =
955 GNUNET_SCHEDULER_add_delayed (timeout,
956 &timeout_task_cb,
957 NULL);
958}
959
960
961/**
962 * The main function to obtain arm from gnunetd.
963 *
964 * @param argc number of arguments from the command line
965 * @param argv command line arguments
966 * @return 0 ok, 1 on error, 2 on timeout
967 */
968int
969main (int argc, char *const *argv)
970{
971 struct GNUNET_GETOPT_CommandLineOption options[] = {
972 GNUNET_GETOPT_option_flag ('e',
973 "end",
974 gettext_noop ("stop all GNUnet services"),
975 &end),
976 GNUNET_GETOPT_option_string ('i',
977 "init",
978 "SERVICE",
979 gettext_noop ("start a particular service"),
980 &init),
981 GNUNET_GETOPT_option_string ('k',
982 "kill",
983 "SERVICE",
984 gettext_noop ("stop a particular service"),
985 &term),
986 GNUNET_GETOPT_option_flag ('a',
987 "all",
988 gettext_noop (
989 "also show stopped services (used with -I)"),
990 &show_all),
991 GNUNET_GETOPT_option_flag ('s',
992 "start",
993 gettext_noop (
994 "start all GNUnet default services"),
995 &start),
996 GNUNET_GETOPT_option_flag ('r',
997 "restart",
998 gettext_noop (
999 "stop and start all GNUnet default services"),
1000 &restart),
1001 GNUNET_GETOPT_option_flag ('d',
1002 "delete",
1003 gettext_noop (
1004 "delete config file and directory on exit"),
1005 &delete),
1006 GNUNET_GETOPT_option_flag ('m',
1007 "monitor",
1008 gettext_noop ("monitor ARM activities"),
1009 &monitor),
1010 GNUNET_GETOPT_option_flag ('q',
1011 "quiet",
1012 gettext_noop ("don't print status messages"),
1013 &quiet),
1014 GNUNET_GETOPT_option_relative_time (
1015 'T',
1016 "timeout",
1017 "DELAY",
1018 gettext_noop (
1019 "exit with error status if operation does not finish after DELAY"),
1020 &timeout),
1021 GNUNET_GETOPT_option_flag ('I',
1022 "info",
1023 gettext_noop (
1024 "list currently running services"),
1025 &list),
1026 GNUNET_GETOPT_option_flag (
1027 'O',
1028 "no-stdout",
1029 gettext_noop ("don't let gnunet-service-arm inherit standard output"),
1030 &no_stdout),
1031 GNUNET_GETOPT_option_flag (
1032 'E',
1033 "no-stderr",
1034 gettext_noop ("don't let gnunet-service-arm inherit standard error"),
1035 &no_stderr),
1036 GNUNET_GETOPT_OPTION_END
1037 };
1038 int lret;
1039
1040 if (GNUNET_OK !=
1041 GNUNET_STRINGS_get_utf8_args (argc,
1042 argv,
1043 &argc,
1044 &argv))
1045 return 2;
1046 if (GNUNET_OK ==
1047 (lret = GNUNET_PROGRAM_run (
1048 argc,
1049 argv,
1050 "gnunet-arm",
1051 gettext_noop (
1052 "Control services and the Automated Restart Manager (ARM)"),
1053 options,
1054 &run,
1055 NULL)))
1056 {
1057 GNUNET_free_nz ((void *) argv);
1058 return ret;
1059 }
1060 GNUNET_free_nz ((void *) argv);
1061 return lret;
1062}
1063
1064
1065/* end of gnunet-arm.c */
diff --git a/src/cli/arm/meson.build b/src/cli/arm/meson.build
new file mode 100644
index 000000000..a50e47ee9
--- /dev/null
+++ b/src/cli/arm/meson.build
@@ -0,0 +1,8 @@
1gnunetarm_src = ['gnunet-arm.c']
2
3executable ('gnunet-arm',
4 gnunetarm_src,
5 dependencies: [libgnunetarm_dep, libgnunetutil_dep],
6 include_directories: [incdir, configuration_inc],
7 install: true,
8 install_dir: get_option('bindir'))
diff --git a/src/cli/cadet/.gitignore b/src/cli/cadet/.gitignore
new file mode 100644
index 000000000..bcd7158aa
--- /dev/null
+++ b/src/cli/cadet/.gitignore
@@ -0,0 +1 @@
gnunet-cadet
diff --git a/src/cli/cadet/Makefile.am b/src/cli/cadet/Makefile.am
new file mode 100644
index 000000000..fc9caa12c
--- /dev/null
+++ b/src/cli/cadet/Makefile.am
@@ -0,0 +1,26 @@
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
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13plugindir = $(libdir)/gnunet
14
15AM_CLFAGS = -g
16
17bin_PROGRAMS = \
18 gnunet-cadet
19
20gnunet_cadet_SOURCES = \
21 gnunet-cadet.c
22gnunet_cadet_LDADD = \
23 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
24 $(top_builddir)/src/lib/util/libgnunetutil.la
25gnunet_cadet_LDFLAGS = \
26 $(GN_LIBINTL)
diff --git a/src/cli/cadet/gnunet-cadet.c b/src/cli/cadet/gnunet-cadet.c
new file mode 100644
index 000000000..c77fb914c
--- /dev/null
+++ b/src/cli/cadet/gnunet-cadet.c
@@ -0,0 +1,851 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2017, 2019 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 cadet/gnunet-cadet.c
23 * @brief Print information about cadet tunnels and peers.
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_cadet_service.h"
30#include "../../service/cadet/cadet.h" // FIXME Smell: this should not be shared like this.
31
32#define STREAM_BUFFER_SIZE 1024 // Pakets
33
34/**
35 * Option -P.
36 */
37static int request_peers;
38
39/**
40 * Option --peer
41 */
42static char *peer_id;
43
44/**
45 * Option -T.
46 */
47static int request_tunnels;
48
49/**
50 * Option --connection
51 */
52static char *conn_id;
53
54/**
55 * Option --channel
56 */
57static char *channel_id;
58
59/**
60 * Port to listen on (-o).
61 */
62static char *listen_port;
63
64/**
65 * Request echo service
66 */
67static int echo;
68
69/**
70 * Time of last echo request.
71 */
72static struct GNUNET_TIME_Absolute echo_time;
73
74/**
75 * Task for next echo request.
76 */
77static struct GNUNET_SCHEDULER_Task *echo_task;
78
79/**
80 * Peer to connect to.
81 */
82static char *target_id;
83
84/**
85 * Port to connect to
86 */
87static char *target_port = "default";
88
89/**
90 * Cadet handle.
91 */
92static struct GNUNET_CADET_Handle *mh;
93
94/**
95 * Our configuration.
96 */
97static const struct GNUNET_CONFIGURATION_Handle *my_cfg;
98
99/**
100 * Active get path operation.
101 */
102static struct GNUNET_CADET_GetPath *gpo;
103
104/**
105 * Active peer listing operation.
106 */
107static struct GNUNET_CADET_PeersLister *plo;
108
109/**
110 * Active tunnel listing operation.
111 */
112static struct GNUNET_CADET_ListTunnels *tio;
113
114/**
115 * Channel handle.
116 */
117static struct GNUNET_CADET_Channel *ch;
118
119/**
120 * HashCode of the given port string
121 */
122static struct GNUNET_HashCode porthash;
123
124/**
125 * Data structure for ongoing reception of incoming virtual circuits.
126 */
127struct GNUNET_CADET_Port *lp;
128
129/**
130 * Task for reading from stdin.
131 */
132static struct GNUNET_SCHEDULER_Task *rd_task;
133
134/**
135 * Task for main job.
136 */
137static struct GNUNET_SCHEDULER_Task *job;
138
139static unsigned int sent_pkt;
140
141
142/**
143 * Wait for input on STDIO and send it out over the #ch.
144 */
145static void
146listen_stdio (void);
147
148
149/**
150 * Convert encryption status to human readable string.
151 *
152 * @param status Encryption status.
153 *
154 * @return Human readable string.
155 */
156static const char *
157enc_2s (uint16_t status)
158{
159 switch (status)
160 {
161 case 0:
162 return "NULL ";
163
164 case 1:
165 return "KSENT";
166
167 case 2:
168 return "KRECV";
169
170 case 3:
171 return "READY";
172
173 default:
174 return "";
175 }
176}
177
178
179/**
180 * Convert connection status to human readable string.
181 *
182 * @param status Connection status.
183 *
184 * @return Human readable string.
185 */
186static const char *
187conn_2s (uint16_t status)
188{
189 switch (status)
190 {
191 case 0:
192 return "NEW ";
193
194 case 1:
195 return "SRCH ";
196
197 case 2:
198 return "WAIT ";
199
200 case 3:
201 return "READY";
202
203 case 4:
204 return "SHUTD";
205
206 default:
207 return "";
208 }
209}
210
211
212/**
213 * Task to shut down this application.
214 *
215 * @param cls Closure (unused).
216 */
217static void
218shutdown_task (void *cls)
219{
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
221 if (NULL != lp)
222 {
223 GNUNET_CADET_close_port (lp);
224 lp = NULL;
225 }
226 if (NULL != ch)
227 {
228 GNUNET_CADET_channel_destroy (ch);
229 ch = NULL;
230 }
231 if (NULL != gpo)
232 {
233 GNUNET_CADET_get_path_cancel (gpo);
234 gpo = NULL;
235 }
236 if (NULL != plo)
237 {
238 GNUNET_CADET_list_peers_cancel (plo);
239 plo = NULL;
240 }
241 if (NULL != tio)
242 {
243 GNUNET_CADET_list_tunnels_cancel (tio);
244 tio = NULL;
245 }
246 if (NULL != mh)
247 {
248 GNUNET_CADET_disconnect (mh);
249 mh = NULL;
250 }
251 if (NULL != rd_task)
252 {
253 GNUNET_SCHEDULER_cancel (rd_task);
254 rd_task = NULL;
255 }
256 if (NULL != echo_task)
257 {
258 GNUNET_SCHEDULER_cancel (echo_task);
259 echo_task = NULL;
260 }
261 if (NULL != job)
262 {
263 GNUNET_SCHEDULER_cancel (job);
264 job = NULL;
265 }
266}
267
268
269void
270mq_cb (void *cls)
271{
272 listen_stdio ();
273}
274
275
276/**
277 * Task run in stdio mode, after some data is available at stdin.
278 *
279 * @param cls Closure (unused).
280 */
281static void
282read_stdio (void *cls)
283{
284 struct GNUNET_MQ_Envelope *env;
285 struct GNUNET_MessageHeader *msg;
286 char buf[60000];
287 ssize_t data_size;
288
289 rd_task = NULL;
290 data_size = read (0, buf, 60000);
291 if (data_size < 1)
292 {
293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294 "read() returned %s\n",
295 strerror (errno));
296 GNUNET_SCHEDULER_shutdown ();
297 return;
298 }
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Read %u bytes from stdio\n",
301 (unsigned int) data_size);
302 env = GNUNET_MQ_msg_extra (msg, data_size, GNUNET_MESSAGE_TYPE_CADET_CLI);
303 GNUNET_memcpy (&msg[1], buf, data_size);
304 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch), env);
305
306 sent_pkt++;
307
308 if (GNUNET_NO == echo)
309 {
310 // Use MQ's notification if too much data of stdin is pooring in too fast.
311 if (STREAM_BUFFER_SIZE < sent_pkt)
312 {
313 GNUNET_MQ_notify_sent (env, mq_cb, cls);
314 sent_pkt = 0;
315 }
316 else
317 {
318 listen_stdio ();
319 }
320 }
321 else
322 {
323 echo_time = GNUNET_TIME_absolute_get ();
324 }
325}
326
327
328/**
329 * Wait for input on STDIO and send it out over the #ch.
330 */
331static void
332listen_stdio ()
333{
334 struct GNUNET_NETWORK_FDSet *rs;
335
336 /* FIXME: why use 'rs' here, seems overly complicated... */
337 rs = GNUNET_NETWORK_fdset_create ();
338 GNUNET_NETWORK_fdset_set_native (rs, 0); /* STDIN */
339 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
340 GNUNET_TIME_UNIT_FOREVER_REL,
341 rs,
342 NULL,
343 &read_stdio,
344 NULL);
345 GNUNET_NETWORK_fdset_destroy (rs);
346}
347
348
349/**
350 * Function called whenever a channel is destroyed. Should clean up
351 * any associated state.
352 *
353 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
354 *
355 * @param cls closure
356 * @param channel connection to the other end (henceforth invalid)
357 */
358static void
359channel_ended (void *cls, const struct GNUNET_CADET_Channel *channel)
360{
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
362 GNUNET_assert (channel == ch);
363 ch = NULL;
364 GNUNET_SCHEDULER_shutdown ();
365}
366
367
368/**
369 * Method called whenever another peer has added us to a channel
370 * the other peer initiated.
371 * Only called (once) upon reception of data with a message type which was
372 * subscribed to in #GNUNET_CADET_connect.
373 *
374 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
375 * In this case the handler MUST return NULL.
376 *
377 * @param cls closure
378 * @param channel new handle to the channel
379 * @param initiator peer that started the channel
380 * @return initial channel context for the channel, we use @a channel
381 */
382static void *
383channel_incoming (void *cls,
384 struct GNUNET_CADET_Channel *channel,
385 const struct GNUNET_PeerIdentity *initiator)
386{
387 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
388 "Incoming connection from %s\n",
389 GNUNET_i2s_full (initiator));
390 GNUNET_assert (NULL == ch);
391 GNUNET_assert (NULL != lp);
392 GNUNET_CADET_close_port (lp);
393 lp = NULL;
394 ch = channel;
395 if (GNUNET_NO == echo)
396 listen_stdio ();
397 return channel;
398}
399
400
401/**
402 * @brief Send an echo request to the remote peer.
403 *
404 * @param cls Closure (NULL).
405 */
406static void
407send_echo (void *cls)
408{
409 struct GNUNET_MQ_Envelope *env;
410 struct GNUNET_MessageHeader *msg;
411
412 echo_task = NULL;
413 if (NULL == ch)
414 return;
415 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_CLI);
416 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch), env);
417}
418
419
420/**
421 * Check data message sanity. Does nothing so far (all messages are OK).
422 *
423 * @param cls Closure (unused).
424 * @param message The message to check.
425 * @return #GNUNET_OK to keep the channel open,
426 * #GNUNET_SYSERR to close it (signal serious error).
427 */
428static int
429check_data (void *cls, const struct GNUNET_MessageHeader *message)
430{
431 return GNUNET_OK; /* all is well-formed */
432}
433
434
435/**
436 * Function called whenever a message is received.
437 *
438 * Each time the function must call #GNUNET_CADET_receive_done on the channel
439 * in order to receive the next message. This doesn't need to be immediate:
440 * can be delayed if some processing is done on the message.
441 *
442 * @param cls NULL
443 * @param message The actual message.
444 */
445static void
446handle_data (void *cls, const struct GNUNET_MessageHeader *message)
447{
448 size_t payload_size = ntohs (message->size) - sizeof(*message);
449 uint16_t len;
450 ssize_t done;
451 uint16_t off;
452 const char *buf;
453
454 GNUNET_CADET_receive_done (ch);
455 if (GNUNET_YES == echo)
456 {
457 if (NULL != listen_port)
458 {
459 struct GNUNET_MQ_Envelope *env;
460 struct GNUNET_MessageHeader *msg;
461
462 env =
463 GNUNET_MQ_msg_extra (msg, payload_size, GNUNET_MESSAGE_TYPE_CADET_CLI);
464 GNUNET_memcpy (&msg[1], &message[1], payload_size);
465 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch), env);
466 return;
467 }
468 else
469 {
470 struct GNUNET_TIME_Relative latency;
471
472 latency = GNUNET_TIME_absolute_get_duration (echo_time);
473 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
474 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
475 "time: %s\n",
476 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
477 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
478 &send_echo,
479 NULL);
480 }
481 }
482
483 len = ntohs (message->size) - sizeof(*message);
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
485 buf = (const char *) &message[1];
486 off = 0;
487 while (off < len)
488 {
489 done = write (1, &buf[off], len - off);
490 if (done <= 0)
491 {
492 if (-1 == done)
493 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
494 GNUNET_SCHEDULER_shutdown ();
495 return;
496 }
497 off += done;
498 }
499}
500
501
502/**
503 * Method called to retrieve information about all peers in CADET, called
504 * once per peer.
505 *
506 * After last peer has been reported, an additional call with NULL is done.
507 *
508 * @param cls Closure.
509 * @param ple information about peer, or NULL on "EOF".
510 */
511static void
512peers_callback (void *cls, const struct GNUNET_CADET_PeerListEntry *ple)
513{
514 if (NULL == ple)
515 {
516 plo = NULL;
517 GNUNET_SCHEDULER_shutdown ();
518 return;
519 }
520 fprintf (stdout,
521 "%s tunnel: %c, paths: %u\n",
522 GNUNET_i2s_full (&ple->peer),
523 ple->have_tunnel ? 'Y' : 'N',
524 ple->n_paths);
525}
526
527
528/**
529 * Method called to retrieve information about paths to a specific peer
530 * known to the service.
531 *
532 * @param cls Closure.
533 * @param ppd path detail
534 */
535static void
536path_callback (void *cls, const struct GNUNET_CADET_PeerPathDetail *ppd)
537{
538 if (NULL == ppd)
539 {
540 gpo = NULL;
541 GNUNET_SCHEDULER_shutdown ();
542 return;
543 }
544 fprintf (stdout, "Path of length %u: ", ppd->path_length);
545 for (unsigned int i = 0; i < ppd->path_length; i++)
546 fprintf (stdout,
547 (i == ppd->target_offset) ? "*%s* " : "%s ",
548 GNUNET_i2s (&ppd->path[i]));
549 fprintf (stdout, "\n");
550}
551
552
553/**
554 * Method called to retrieve information about all tunnels in CADET.
555 *
556 * @param cls Closure.
557 * @param td tunnel details
558 */
559static void
560tunnels_callback (void *cls, const struct GNUNET_CADET_TunnelDetails *td)
561{
562 if (NULL == td)
563 {
564 tio = NULL;
565 GNUNET_SCHEDULER_shutdown ();
566 return;
567 }
568 fprintf (stdout,
569 "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
570 GNUNET_i2s_full (&td->peer),
571 enc_2s (td->estate),
572 conn_2s (td->cstate),
573 td->channels,
574 td->connections);
575}
576
577
578/**
579 * Call CADET's meta API, get all peers known to a peer.
580 *
581 * @param cls Closure (unused).
582 */
583static void
584get_peers (void *cls)
585{
586 job = NULL;
587 plo = GNUNET_CADET_list_peers (my_cfg, &peers_callback, NULL);
588}
589
590
591/**
592 * Call CADET's monitor API, get info of one peer.
593 *
594 * @param cls Closure (unused).
595 */
596static void
597show_peer (void *cls)
598{
599 struct GNUNET_PeerIdentity pid;
600
601 job = NULL;
602 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
603 strlen (peer_id),
604 &pid.public_key))
605 {
606 fprintf (stderr, _ ("Invalid peer ID `%s'\n"), peer_id);
607 GNUNET_SCHEDULER_shutdown ();
608 return;
609 }
610 gpo = GNUNET_CADET_get_path (my_cfg, &pid, &path_callback, NULL);
611}
612
613
614/**
615 * Call CADET's meta API, get all tunnels known to a peer.
616 *
617 * @param cls Closure (unused).
618 */
619static void
620get_tunnels (void *cls)
621{
622 job = NULL;
623 tio = GNUNET_CADET_list_tunnels (my_cfg, &tunnels_callback, NULL);
624}
625
626
627/**
628 * Call CADET's monitor API, get info of one channel.
629 *
630 * @param cls Closure (unused).
631 */
632static void
633show_channel (void *cls)
634{
635 job = NULL;
636 GNUNET_break (0);
637}
638
639
640/**
641 * Call CADET's monitor API, get info of one connection.
642 *
643 * @param cls Closure (unused).
644 */
645static void
646show_connection (void *cls)
647{
648 job = NULL;
649 GNUNET_break (0);
650}
651
652
653/**
654 * Main function that will be run by the scheduler.
655 *
656 * @param cls closure
657 * @param args remaining command-line arguments
658 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
659 * @param cfg configuration
660 */
661static void
662run (void *cls,
663 char *const *args,
664 const char *cfgfile,
665 const struct GNUNET_CONFIGURATION_Handle *cfg)
666{
667 struct GNUNET_MQ_MessageHandler handlers[] =
668 { GNUNET_MQ_hd_var_size (data,
669 GNUNET_MESSAGE_TYPE_CADET_CLI,
670 struct GNUNET_MessageHeader,
671 NULL),
672 GNUNET_MQ_handler_end () };
673
674 /* FIXME add option to monitor apps */
675 my_cfg = cfg;
676 target_id = args[0];
677 if (target_id && args[1])
678 target_port = args[1];
679
680 if (((0 != (request_peers | request_tunnels)) || (NULL != conn_id) ||
681 (NULL != channel_id) ) &&
682 (target_id != NULL) )
683 {
684 fprintf (stderr,
685 _ ("Extra arguments are not applicable "
686 "in combination with this option.\n"));
687 return;
688 }
689
690 if (NULL != peer_id)
691 {
692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
693 job = GNUNET_SCHEDULER_add_now (&show_peer, NULL);
694 }
695 else if (NULL != channel_id)
696 {
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
698 job = GNUNET_SCHEDULER_add_now (&show_channel, NULL);
699 }
700 else if (NULL != conn_id)
701 {
702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
703 job = GNUNET_SCHEDULER_add_now (&show_connection, NULL);
704 }
705 else if (GNUNET_YES == request_peers)
706 {
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
708 job = GNUNET_SCHEDULER_add_now (&get_peers, NULL);
709 }
710 else if (GNUNET_YES == request_tunnels)
711 {
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
713 job = GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
714 }
715
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET service\n");
717 mh = GNUNET_CADET_connect (cfg);
718 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
719 if (NULL == mh)
720 {
721 GNUNET_SCHEDULER_shutdown ();
722 return;
723 }
724 if (NULL != listen_port)
725 {
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET listen port\n");
727 GNUNET_CRYPTO_hash (listen_port, strlen (listen_port), &porthash);
728 lp = GNUNET_CADET_open_port (mh,
729 &porthash,
730 &channel_incoming,
731 NULL,
732 NULL /* window changes */,
733 &channel_ended,
734 handlers);
735 }
736 if (NULL != target_id)
737 {
738 struct GNUNET_PeerIdentity pid;
739
740 if (GNUNET_OK !=
741 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
742 strlen (target_id),
743 &pid.public_key))
744 {
745 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
746 _ ("Invalid target `%s'\n"),
747 target_id);
748 GNUNET_SCHEDULER_shutdown ();
749 return;
750 }
751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
752 "Connecting to `%s:%s'\n",
753 target_id,
754 target_port);
755 GNUNET_CRYPTO_hash (target_port, strlen (target_port), &porthash);
756 ch = GNUNET_CADET_channel_create (mh,
757 NULL,
758 &pid,
759 &porthash,
760 NULL /* window changes */,
761 &channel_ended,
762 handlers);
763 if (GNUNET_YES == echo)
764 {
765 echo_task = GNUNET_SCHEDULER_add_now (&send_echo, NULL);
766 }
767 else
768 {
769 listen_stdio ();
770 }
771 }
772
773 if ((NULL == lp) && (NULL == job) && (NULL == ch))
774 {
775 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, _ ("No action requested\n"));
776 GNUNET_SCHEDULER_shutdown ();
777 return;
778 }
779}
780
781
782/**
783 * The main function to obtain peer information.
784 *
785 * @param argc number of arguments from the command line
786 * @param argv command line arguments
787 * @return 0 ok, 1 on error
788 */
789int
790main (int argc, char *const *argv)
791{
792 int res;
793 const char helpstr[] =
794 "Create tunnels and retrieve info about CADET's status.";
795 struct GNUNET_GETOPT_CommandLineOption options[] = { /* I would use the terminology 'circuit' here... --lynX */
796 GNUNET_GETOPT_option_string (
797 'C',
798 "connection",
799 "CONNECTION_ID",
800 gettext_noop ("Provide information about a particular connection"),
801 &conn_id),
802 GNUNET_GETOPT_option_flag ('e',
803 "echo",
804 gettext_noop ("Activate echo mode"),
805 &echo),
806 GNUNET_GETOPT_option_string (
807 'o',
808 "open-port",
809 "SHARED_SECRET",
810 gettext_noop (
811 "Listen for connections using a shared secret among sender and recipient"),
812 &listen_port),
813 GNUNET_GETOPT_option_string ('p',
814 "peer",
815 "PEER_ID",
816 gettext_noop (
817 "Provide information about a patricular peer"),
818 &peer_id),
819 GNUNET_GETOPT_option_flag ('P',
820 "peers",
821 gettext_noop (
822 "Provide information about all peers"),
823 &request_peers),
824 GNUNET_GETOPT_option_flag ('T',
825 "tunnels",
826 gettext_noop (
827 "Provide information about all tunnels"),
828 &request_tunnels),
829 GNUNET_GETOPT_OPTION_END
830 };
831
832 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
833 return 2;
834
835 res = GNUNET_PROGRAM_run (argc,
836 argv,
837 "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
838 gettext_noop (helpstr),
839 options,
840 &run,
841 NULL);
842
843 GNUNET_free_nz ((void *) argv);
844
845 if (GNUNET_OK == res)
846 return 0;
847 return 1;
848}
849
850
851/* end of gnunet-cadet.c */
diff --git a/src/cli/cadet/meson.build b/src/cli/cadet/meson.build
new file mode 100644
index 000000000..09a1965ac
--- /dev/null
+++ b/src/cli/cadet/meson.build
@@ -0,0 +1,15 @@
1executable ('gnunet-cadet',
2 ['gnunet-cadet.c'],
3 dependencies: [libgnunetcadet_dep,
4 libgnunetutil_dep,
5 libgnunetcore_dep,
6 libgnunetdht_dep,
7 m_dep,
8 libgnunetstatistics_dep,
9 libgnunetpeerstore_dep,
10 libgnunettransportapplication_dep,
11 libgnunethello_dep],
12 include_directories: [incdir, configuration_inc],
13 install: true,
14 install_dir: get_option('bindir'))
15
diff --git a/src/cli/core/.gitignore b/src/cli/core/.gitignore
new file mode 100644
index 000000000..95169ed2b
--- /dev/null
+++ b/src/cli/core/.gitignore
@@ -0,0 +1 @@
gnunet-core
diff --git a/src/cli/core/Makefile.am b/src/cli/core/Makefile.am
new file mode 100644
index 000000000..97abf0db2
--- /dev/null
+++ b/src/cli/core/Makefile.am
@@ -0,0 +1,24 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6plugindir = $(libdir)/gnunet
7
8libexecdir= $(pkglibdir)/libexec/
9
10if USE_COVERAGE
11 AM_CFLAGS = --coverage -O0
12 XLIB = -lgcov
13endif
14
15bin_PROGRAMS = \
16 gnunet-core
17
18gnunet_core_SOURCES = \
19 gnunet-core.c
20gnunet_core_LDADD = \
21 $(top_builddir)/src/service/core/libgnunetcore.la \
22 $(top_builddir)/src/lib/util/libgnunetutil.la
23gnunet_core_LDFLAGS = \
24 $(GN_LIBINTL)
diff --git a/src/cli/core/gnunet-core.c b/src/cli/core/gnunet-core.c
new file mode 100644
index 000000000..00b08eefc
--- /dev/null
+++ b/src/cli/core/gnunet-core.c
@@ -0,0 +1,274 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2012, 2014 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 core/gnunet-core.c
23 * @brief Print information about other peers known to CORE.
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_core_service.h"
29
30
31/**
32 * Option -m.
33 */
34static int monitor_connections;
35
36/**
37 * Option -i.
38 */
39static int show_pid;
40
41/**
42 * Option -s.
43 */
44static int show_conns;
45
46/**
47 * Handle to the CORE monitor.
48 */
49static struct GNUNET_CORE_MonitorHandle *mh;
50
51
52/**
53 * Task run in monitor mode when the user presses CTRL-C to abort.
54 * Stops monitoring activity.
55 *
56 * @param cls NULL
57 */
58static void
59shutdown_task (void *cls)
60{
61 (void) cls;
62 if (NULL != mh)
63 {
64 GNUNET_CORE_monitor_stop (mh);
65 mh = NULL;
66 }
67}
68
69
70/**
71 * Function called to notify core users that another
72 * peer changed its state with us.
73 *
74 * @param cls closure
75 * @param peer the peer that changed state
76 * @param state new state of the peer
77 * @param timeout timeout for the new state
78 */
79static void
80monitor_cb (void *cls,
81 const struct GNUNET_PeerIdentity *peer,
82 enum GNUNET_CORE_KxState state,
83 struct GNUNET_TIME_Absolute timeout)
84{
85 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
86 const char *now_str;
87 const char *state_str;
88
89 (void) cls;
90 if (((NULL == peer) || (GNUNET_CORE_KX_ITERATION_FINISHED == state)) &&
91 (GNUNET_NO == monitor_connections))
92 {
93 GNUNET_SCHEDULER_shutdown ();
94 return;
95 }
96
97 switch (state)
98 {
99 case GNUNET_CORE_KX_STATE_DOWN:
100 /* should never happen, as we immediately send the key */
101 state_str = _ ("fresh connection");
102 break;
103
104 case GNUNET_CORE_KX_STATE_KEY_SENT:
105 state_str = _ ("key sent");
106 break;
107
108 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
109 state_str = _ ("key received");
110 break;
111
112 case GNUNET_CORE_KX_STATE_UP:
113 state_str = _ ("connection established");
114 break;
115
116 case GNUNET_CORE_KX_STATE_REKEY_SENT:
117 state_str = _ ("rekeying");
118 break;
119
120 case GNUNET_CORE_KX_PEER_DISCONNECT:
121 state_str = _ ("disconnected");
122 break;
123
124 case GNUNET_CORE_KX_ITERATION_FINISHED:
125 return;
126
127 case GNUNET_CORE_KX_CORE_DISCONNECT:
128 fprintf (stderr,
129 "%s\n",
130 _ ("Connection to CORE service lost (reconnecting)"));
131 return;
132
133 default:
134 state_str = _ ("unknown state");
135 break;
136 }
137 now_str = GNUNET_STRINGS_absolute_time_to_string (now);
138 fprintf (stdout,
139 _ ("%24s: %-30s %4s (timeout in %6s)\n"),
140 now_str,
141 state_str,
142 GNUNET_i2s (peer),
143 GNUNET_STRINGS_relative_time_to_string (
144 GNUNET_TIME_absolute_get_remaining (timeout),
145 GNUNET_YES));
146}
147
148
149/**
150 * Main function that will be run by the scheduler.
151 *
152 * @param cls closure
153 * @param args remaining command-line arguments
154 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
155 * @param cfg configuration
156 */
157static void
158run (void *cls,
159 char *const *args,
160 const char *cfgfile,
161 const struct GNUNET_CONFIGURATION_Handle *cfg)
162{
163 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
164 struct GNUNET_CRYPTO_EddsaPublicKey pub;
165 char *keyfile;
166 (void) cls;
167 (void) cfgfile;
168 if (NULL != args[0])
169 {
170 fprintf (stderr, _ ("Invalid command line argument `%s'\n"), args[0]);
171 return;
172 }
173 if (GNUNET_OK !=
174 GNUNET_CONFIGURATION_get_value_filename (cfg,
175 "PEER",
176 "PRIVATE_KEY",
177 &keyfile))
178 {
179 GNUNET_log (
180 GNUNET_ERROR_TYPE_ERROR,
181 _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
182 GNUNET_SCHEDULER_shutdown ();
183 return;
184 }
185 if (GNUNET_SYSERR ==
186 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
187 GNUNET_YES,
188 &pk))
189 {
190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
191 "Failed to read peer's private key!\n");
192 GNUNET_SCHEDULER_shutdown ();
193 GNUNET_free (keyfile);
194 return;
195 }
196 GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub);
197 if (show_pid)
198 fprintf (stdout,
199 _ ("Current local peer identity: %s\n"),
200 GNUNET_i2s_full ((struct GNUNET_PeerIdentity*) &pub));
201 if (show_conns || monitor_connections)
202 {
203 mh = GNUNET_CORE_monitor_start (cfg, &monitor_cb, NULL);
204 if (NULL == mh)
205 {
206 fprintf (stderr, "%s", _ ("Failed to connect to CORE service!\n"));
207 GNUNET_free (keyfile);
208 return;
209 }
210 }
211 if (! show_pid && ! show_conns && ! monitor_connections)
212 {
213 fprintf (stderr, "%s", _ ("No argument given.\n"));
214 GNUNET_free (keyfile);
215 return;
216 }
217 GNUNET_free (keyfile);
218 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
219}
220
221
222/**
223 * The main function to obtain peer information from CORE.
224 *
225 * @param argc number of arguments from the command line
226 * @param argv command line arguments
227 * @return 0 ok, 1 on error
228 */
229int
230main (int argc, char *const *argv)
231{
232 int res;
233 struct GNUNET_GETOPT_CommandLineOption options[] =
234 { GNUNET_GETOPT_option_flag (
235 'm',
236 "monitor",
237 gettext_noop (
238 "provide information about all current connections (continuously)"),
239 &monitor_connections),
240 GNUNET_GETOPT_option_flag (
241 'i',
242 "show-identity",
243 gettext_noop (
244 "Show our current peer identity"
245 ),
246 &show_pid),
247 GNUNET_GETOPT_option_flag (
248 's',
249 "connection-status",
250 gettext_noop (
251 "Show current connections"
252 ),
253 &show_conns),
254 GNUNET_GETOPT_OPTION_END };
255
256 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
257 return 2;
258 res = GNUNET_PROGRAM_run (argc,
259 argv,
260 "gnunet-core",
261 gettext_noop (
262 "Print information about connected peers."),
263 options,
264 &run,
265 NULL);
266
267 GNUNET_free_nz ((void *) argv);
268 if (GNUNET_OK == res)
269 return 0;
270 return 1;
271}
272
273
274/* end of gnunet-core.c */
diff --git a/src/cli/core/meson.build b/src/cli/core/meson.build
new file mode 100644
index 000000000..db246a3c4
--- /dev/null
+++ b/src/cli/core/meson.build
@@ -0,0 +1,6 @@
1executable ('gnunet-core',
2 ['gnunet-core.c'],
3 dependencies: [libgnunetcore_dep, libgnunetutil_dep],
4 include_directories: [incdir, configuration_inc],
5 install: true,
6 install_dir: get_option('bindir'))
diff --git a/src/cli/datastore/.gitignore b/src/cli/datastore/.gitignore
new file mode 100644
index 000000000..ddb105175
--- /dev/null
+++ b/src/cli/datastore/.gitignore
@@ -0,0 +1 @@
gnunet-datastore
diff --git a/src/cli/datastore/Makefile.am b/src/cli/datastore/Makefile.am
new file mode 100644
index 000000000..91098db96
--- /dev/null
+++ b/src/cli/datastore/Makefile.am
@@ -0,0 +1,24 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10if USE_COVERAGE
11 AM_CFLAGS = --coverage -O0
12 XLIBS = -lgcov
13endif
14
15
16bin_PROGRAMS = \
17 gnunet-datastore
18
19gnunet_datastore_SOURCES = \
20 gnunet-datastore.c
21gnunet_datastore_LDADD = \
22 $(top_builddir)/src/service/datastore/libgnunetdatastore.la \
23 $(top_builddir)/src/lib/util/libgnunetutil.la \
24 $(GN_LIBINTL)
diff --git a/src/cli/datastore/gnunet-datastore.c b/src/cli/datastore/gnunet-datastore.c
new file mode 100644
index 000000000..9a76d1160
--- /dev/null
+++ b/src/cli/datastore/gnunet-datastore.c
@@ -0,0 +1,508 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2013 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 datastore/gnunet-datastore.c
23 * @brief tool to manipulate datastores
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <inttypes.h>
28#include "gnunet_util_lib.h"
29#include "gnunet_datastore_service.h"
30
31GNUNET_NETWORK_STRUCT_BEGIN
32
33struct DataRecord
34{
35 /**
36 * Number of bytes in the item (NBO).
37 */
38 uint32_t size GNUNET_PACKED;
39
40 /**
41 * Type of the item (NBO) (actually an enum GNUNET_BLOCK_Type)
42 */
43 uint32_t type GNUNET_PACKED;
44
45 /**
46 * Priority of the item (NBO).
47 */
48 uint32_t priority GNUNET_PACKED;
49
50 /**
51 * Desired anonymity level (NBO).
52 */
53 uint32_t anonymity GNUNET_PACKED;
54
55 /**
56 * Desired replication level (NBO).
57 */
58 uint32_t replication GNUNET_PACKED;
59
60 /**
61 * Expiration time (NBO).
62 */
63 struct GNUNET_TIME_AbsoluteNBO expiration;
64
65 /**
66 * Key under which the item can be found.
67 */
68 struct GNUNET_HashCode key;
69};
70GNUNET_NETWORK_STRUCT_END
71
72
73/**
74 * Length of our magic header.
75 */
76static const size_t MAGIC_LEN = 16;
77
78/**
79 * Magic header bytes.
80 */
81static const uint8_t MAGIC_BYTES[16] = "GNUNETDATASTORE1";
82
83/**
84 * Dump the database.
85 */
86static int dump;
87
88/**
89 * Insert into the database.
90 */
91static int insert;
92
93/**
94 * Dump file name.
95 */
96static char *file_name;
97
98/**
99 * Dump file handle.
100 */
101static struct GNUNET_DISK_FileHandle *file_handle;
102
103/**
104 * Global return value.
105 */
106static int ret;
107
108/**
109 * Handle for datastore.
110 */
111static struct GNUNET_DATASTORE_Handle *datastore;
112
113/**
114 * Current operation.
115 */
116static struct GNUNET_DATASTORE_QueueEntry *qe;
117
118/**
119 * Record count.
120 */
121static uint64_t record_count;
122
123
124static void
125do_shutdown (void *cls)
126{
127 if (NULL != qe)
128 GNUNET_DATASTORE_cancel (qe);
129 if (NULL != datastore)
130 GNUNET_DATASTORE_disconnect (datastore, GNUNET_NO);
131 if (NULL != file_handle)
132 GNUNET_DISK_file_close (file_handle);
133}
134
135
136/**
137 * Begin dumping the database.
138 */
139static void
140start_dump (void);
141
142
143/**
144 * Begin inserting into the database.
145 */
146static void
147start_insert (void);
148
149
150/**
151 * Perform next GET operation.
152 */
153static void
154do_get (const uint64_t next_uid);
155
156
157/**
158 * Process a datum that was stored in the datastore.
159 *
160 * @param cls closure
161 * @param key key for the content
162 * @param size number of bytes in data
163 * @param data content stored
164 * @param type type of the content
165 * @param priority priority of the content
166 * @param anonymity anonymity-level for the content
167 * @param replication replication-level for the content
168 * @param expiration expiration time for the content
169 * @param uid unique identifier for the datum;
170 * maybe 0 if no unique identifier is available
171 */
172static void
173get_cb (void *cls,
174 const struct GNUNET_HashCode *key,
175 size_t size,
176 const void *data,
177 enum GNUNET_BLOCK_Type type,
178 uint32_t priority,
179 uint32_t anonymity,
180 uint32_t replication,
181 struct GNUNET_TIME_Absolute expiration,
182 uint64_t uid)
183{
184 qe = NULL;
185 if (NULL == key)
186 {
187 fprintf (stderr, _ ("Dumped %" PRIu64 " records\n"), record_count);
188 GNUNET_DISK_file_close (file_handle);
189 file_handle = NULL;
190 if (insert)
191 start_insert ();
192 else
193 {
194 ret = 0;
195 GNUNET_SCHEDULER_shutdown ();
196 }
197 return;
198 }
199
200 struct DataRecord dr;
201 dr.size = htonl ((uint32_t) size);
202 dr.type = htonl (type);
203 dr.priority = htonl (priority);
204 dr.anonymity = htonl (anonymity);
205 dr.replication = htonl (replication);
206 dr.expiration = GNUNET_TIME_absolute_hton (expiration);
207 dr.key = *key;
208
209 ssize_t len;
210 len = GNUNET_DISK_file_write (file_handle, &dr, sizeof(dr));
211 if (sizeof(dr) != len)
212 {
213 fprintf (stderr,
214 _ ("Short write to file: %zd bytes expecting %zd\n"),
215 len,
216 sizeof(dr));
217 ret = 1;
218 GNUNET_SCHEDULER_shutdown ();
219 return;
220 }
221
222 len = GNUNET_DISK_file_write (file_handle, data, size);
223 if (size != len)
224 {
225 fprintf (stderr,
226 _ ("Short write to file: %zd bytes expecting %zd\n"),
227 len,
228 size);
229 ret = 1;
230 GNUNET_SCHEDULER_shutdown ();
231 return;
232 }
233
234 record_count++;
235 do_get (uid + 1);
236}
237
238
239/**
240 * Perform next GET operation.
241 */
242static void
243do_get (const uint64_t next_uid)
244{
245 GNUNET_assert (NULL == qe);
246 qe = GNUNET_DATASTORE_get_key (datastore,
247 next_uid,
248 false /* random */,
249 NULL /* key */,
250 GNUNET_BLOCK_TYPE_ANY,
251 0 /* queue_priority */,
252 1 /* max_queue_size */,
253 &get_cb,
254 NULL /* proc_cls */);
255 if (NULL == qe)
256 {
257 fprintf (stderr, _ ("Error queueing datastore GET operation\n"));
258 ret = 1;
259 GNUNET_SCHEDULER_shutdown ();
260 }
261}
262
263
264/**
265 * Begin dumping the database.
266 */
267static void
268start_dump ()
269{
270 record_count = 0;
271
272 if (NULL != file_name)
273 {
274 file_handle = GNUNET_DISK_file_open (file_name,
275 GNUNET_DISK_OPEN_WRITE
276 | GNUNET_DISK_OPEN_TRUNCATE
277 | GNUNET_DISK_OPEN_CREATE,
278 GNUNET_DISK_PERM_USER_READ
279 | GNUNET_DISK_PERM_USER_WRITE);
280 if (NULL == file_handle)
281 {
282 fprintf (stderr, _ ("Unable to open dump file: %s\n"), file_name);
283 ret = 1;
284 GNUNET_SCHEDULER_shutdown ();
285 return;
286 }
287 }
288 else
289 {
290 file_handle = GNUNET_DISK_get_handle_from_int_fd (STDOUT_FILENO);
291 }
292 GNUNET_DISK_file_write (file_handle, MAGIC_BYTES, MAGIC_LEN);
293 do_get (0);
294}
295
296
297/**
298 * Continuation called to notify client about result of the
299 * operation.
300 *
301 * @param cls closure
302 * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
303 * GNUNET_NO if content was already there
304 * GNUNET_YES (or other positive value) on success
305 * @param min_expiration minimum expiration time required for 0-priority content to be stored
306 * by the datacache at this time, zero for unknown, forever if we have no
307 * space for 0-priority content
308 * @param msg NULL on success, otherwise an error message
309 */
310static void
311put_cb (void *cls,
312 int32_t success,
313 struct GNUNET_TIME_Absolute min_expiration,
314 const char *msg)
315{
316 qe = NULL;
317 if (GNUNET_SYSERR == success)
318 {
319 fprintf (stderr, _ ("Failed to store item: %s, aborting\n"), msg);
320 ret = 1;
321 GNUNET_SCHEDULER_shutdown ();
322 return;
323 }
324
325 struct DataRecord dr;
326 ssize_t len;
327
328 len = GNUNET_DISK_file_read (file_handle, &dr, sizeof(dr));
329 if (0 == len)
330 {
331 fprintf (stderr, _ ("Inserted %" PRIu64 " records\n"), record_count);
332 ret = 0;
333 GNUNET_SCHEDULER_shutdown ();
334 return;
335 }
336 else if (sizeof(dr) != len)
337 {
338 fprintf (stderr,
339 _ ("Short read from file: %zd bytes expecting %zd\n"),
340 len,
341 sizeof(dr));
342 ret = 1;
343 GNUNET_SCHEDULER_shutdown ();
344 return;
345 }
346
347 const size_t size = ntohl (dr.size);
348 uint8_t data[size];
349 len = GNUNET_DISK_file_read (file_handle, data, size);
350 if (size != len)
351 {
352 fprintf (stderr,
353 _ ("Short read from file: %zd bytes expecting %zd\n"),
354 len,
355 size);
356 ret = 1;
357 GNUNET_SCHEDULER_shutdown ();
358 return;
359 }
360
361 record_count++;
362 qe = GNUNET_DATASTORE_put (datastore,
363 0,
364 &dr.key,
365 size,
366 data,
367 ntohl (dr.type),
368 ntohl (dr.priority),
369 ntohl (dr.anonymity),
370 ntohl (dr.replication),
371 GNUNET_TIME_absolute_ntoh (dr.expiration),
372 0,
373 1,
374 &put_cb,
375 NULL);
376 if (NULL == qe)
377 {
378 fprintf (stderr, _ ("Error queueing datastore PUT operation\n"));
379 ret = 1;
380 GNUNET_SCHEDULER_shutdown ();
381 }
382}
383
384
385/**
386 * Begin inserting into the database.
387 */
388static void
389start_insert ()
390{
391 record_count = 0;
392
393 if (NULL != file_name)
394 {
395 file_handle = GNUNET_DISK_file_open (file_name,
396 GNUNET_DISK_OPEN_READ,
397 GNUNET_DISK_PERM_NONE);
398 if (NULL == file_handle)
399 {
400 fprintf (stderr, _ ("Unable to open dump file: %s\n"), file_name);
401 ret = 1;
402 GNUNET_SCHEDULER_shutdown ();
403 return;
404 }
405 }
406 else
407 {
408 file_handle = GNUNET_DISK_get_handle_from_int_fd (STDIN_FILENO);
409 }
410
411 uint8_t buf[MAGIC_LEN];
412 ssize_t len;
413
414 len = GNUNET_DISK_file_read (file_handle, buf, MAGIC_LEN);
415 if ((len != MAGIC_LEN) || (0 != memcmp (buf, MAGIC_BYTES, MAGIC_LEN)))
416 {
417 fprintf (stderr, _ ("Input file is not of a supported format\n"));
418 return;
419 }
420 put_cb (NULL, GNUNET_YES, GNUNET_TIME_UNIT_ZERO_ABS, NULL);
421}
422
423
424/**
425 * Main function that will be run by the scheduler.
426 *
427 * @param cls closure
428 * @param args remaining command-line arguments
429 * @param cfgfile name of the configuration file used
430 * @param cfg configuration
431 */
432static void
433run (void *cls,
434 char *const *args,
435 const char *cfgfile,
436 const struct GNUNET_CONFIGURATION_Handle *cfg)
437{
438 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
439 datastore = GNUNET_DATASTORE_connect (cfg);
440 if (NULL == datastore)
441 {
442 fprintf (stderr, _ ("Failed connecting to the datastore.\n"));
443 ret = 1;
444 GNUNET_SCHEDULER_shutdown ();
445 return;
446 }
447 if (dump)
448 start_dump ();
449 else if (insert)
450 start_insert ();
451 else
452 {
453 fprintf (stderr,
454 _ ("Please choose at least one operation: %s, %s\n"),
455 "dump",
456 "insert");
457 ret = 1;
458 GNUNET_SCHEDULER_shutdown ();
459 }
460}
461
462
463/**
464 * The main function to manipulate datastores.
465 *
466 * @param argc number of arguments from the command line
467 * @param argv command line arguments
468 * @return 0 ok, 1 on error
469 */
470int
471main (int argc, char *const *argv)
472{
473 struct GNUNET_GETOPT_CommandLineOption options[] =
474 { GNUNET_GETOPT_option_flag ('d',
475 "dump",
476 gettext_noop (
477 "Dump all records from the datastore"),
478 &dump),
479 GNUNET_GETOPT_option_flag ('i',
480 "insert",
481 gettext_noop (
482 "Insert records into the datastore"),
483 &insert),
484 GNUNET_GETOPT_option_filename ('f',
485 "file",
486 "FILENAME",
487 gettext_noop ("File to dump or insert"),
488 &file_name),
489 GNUNET_GETOPT_OPTION_END };
490
491 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
492 return 2;
493
494 if (GNUNET_OK !=
495 GNUNET_PROGRAM_run (argc,
496 argv,
497 "gnunet-datastore",
498 gettext_noop ("Manipulate GNUnet datastore"),
499 options,
500 &run,
501 NULL))
502 ret = 1;
503 GNUNET_free_nz ((void *) argv);
504 return ret;
505}
506
507
508/* end of gnunet-datastore.c */
diff --git a/src/cli/datastore/meson.build b/src/cli/datastore/meson.build
new file mode 100644
index 000000000..7ec8eec47
--- /dev/null
+++ b/src/cli/datastore/meson.build
@@ -0,0 +1,9 @@
1executable ('gnunet-datastore',
2 ['gnunet-datastore.c'],
3 dependencies: [libgnunetdatastore_dep,
4 libgnunetutil_dep,
5 libgnunetstatistics_dep,
6 libgnunetdatacache_dep],
7 include_directories: [incdir, configuration_inc],
8 install: true,
9 install_dir: get_option('bindir'))
diff --git a/src/cli/dht/.gitignore b/src/cli/dht/.gitignore
new file mode 100644
index 000000000..3b6564ef0
--- /dev/null
+++ b/src/cli/dht/.gitignore
@@ -0,0 +1,5 @@
1gnunet-dht-get
2gnunet-dht-monitor
3gnunet-dht-profiler
4gnunet-dht-put
5gnunet-dht-hello
diff --git a/src/cli/dht/Makefile.am b/src/cli/dht/Makefile.am
new file mode 100644
index 000000000..f026b5270
--- /dev/null
+++ b/src/cli/dht/Makefile.am
@@ -0,0 +1,52 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10if USE_COVERAGE
11 AM_CFLAGS = --coverage -O0
12 XLIB = -lgcov
13endif
14
15bin_PROGRAMS = \
16 gnunet-dht-monitor \
17 gnunet-dht-get \
18 gnunet-dht-put \
19 gnunet-dht-hello
20
21gnunet_dht_get_SOURCES = \
22 gnunet-dht-get.c
23gnunet_dht_get_LDADD = \
24 $(top_builddir)/src/service/dht/libgnunetdht.la \
25 $(top_builddir)/src/lib/util/libgnunetutil.la
26gnunet_dht_get_LDFLAGS = \
27 $(GN_LIBINTL)
28
29gnunet_dht_hello_SOURCES = \
30 gnunet-dht-hello.c
31gnunet_dht_hello_LDADD = \
32 $(top_builddir)/src/service/dht/libgnunetdht.la \
33 $(top_builddir)/src/lib/util/libgnunetutil.la
34gnunet_dht_hello_LDFLAGS = \
35 $(GN_LIBINTL)
36
37gnunet_dht_put_SOURCES = \
38 gnunet-dht-put.c
39gnunet_dht_put_LDADD = \
40 $(top_builddir)/src/service/dht/libgnunetdht.la \
41 $(top_builddir)/src/lib/util/libgnunetutil.la
42gnunet_dht_put_LDFLAGS = \
43 $(GN_LIBINTL)
44
45gnunet_dht_monitor_SOURCES = \
46 gnunet-dht-monitor.c
47gnunet_dht_monitor_LDADD = \
48 $(top_builddir)/src/service/dht/libgnunetdht.la \
49 $(top_builddir)/src/lib/util/libgnunetutil.la
50gnunet_dht_monitor_LDFLAGS = \
51 $(GN_LIBINTL)
52
diff --git a/src/cli/dht/gnunet-dht-get.c b/src/cli/dht/gnunet-dht-get.c
new file mode 100644
index 000000000..393184bb6
--- /dev/null
+++ b/src/cli/dht/gnunet-dht-get.c
@@ -0,0 +1,352 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 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 dht/gnunet-dht-get.c
22 * @brief search for data in DHT
23 * @author Christian Grothoff
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_dht_service.h"
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "dht-clients", __VA_ARGS__)
30/**
31 * The type of the query
32 */
33static unsigned int query_type;
34
35/**
36 * Desired replication level
37 */
38static unsigned int replication = 5;
39
40/**
41 * The key for the query
42 */
43static char *query_key;
44
45/**
46 * User supplied timeout value
47 */
48static struct GNUNET_TIME_Relative timeout_request = { 60000 };
49
50/**
51 * Be verbose
52 */
53static unsigned int verbose;
54
55/**
56 * Use DHT demultixplex_everywhere
57 */
58static int demultixplex_everywhere;
59
60/**
61 * Use #GNUNET_DHT_RO_RECORD_ROUTE.
62 */
63static int record_route;
64
65/**
66 * Handle to the DHT
67 */
68static struct GNUNET_DHT_Handle *dht_handle;
69
70/**
71 * Global handle of the configuration
72 */
73static const struct GNUNET_CONFIGURATION_Handle *cfg;
74
75/**
76 * Handle for the get request
77 */
78static struct GNUNET_DHT_GetHandle *get_handle;
79
80/**
81 * Count of results found
82 */
83static unsigned int result_count;
84
85/**
86 * Global status value
87 */
88static int ret;
89
90/**
91 * Task scheduled to handle timeout.
92 */
93static struct GNUNET_SCHEDULER_Task *tt;
94
95
96/**
97 * Task run to clean up on shutdown.
98 *
99 * @param cls unused
100 */
101static void
102cleanup_task (void *cls)
103{
104 if (NULL != get_handle)
105 {
106 GNUNET_DHT_get_stop (get_handle);
107 get_handle = NULL;
108 }
109 if (NULL != dht_handle)
110 {
111 GNUNET_DHT_disconnect (dht_handle);
112 dht_handle = NULL;
113 }
114 if (NULL != tt)
115 {
116 GNUNET_SCHEDULER_cancel (tt);
117 tt = NULL;
118 }
119}
120
121
122/**
123 * Task run on timeout. Triggers shutdown.
124 *
125 * @param cls unused
126 */
127static void
128timeout_task (void *cls)
129{
130 tt = NULL;
131 GNUNET_SCHEDULER_shutdown ();
132}
133
134
135/**
136 * Iterator called on each result obtained for a DHT
137 * operation that expects a reply
138 *
139 * @param cls closure
140 * @param exp when will this value expire
141 * @param key key of the result
142 * @param trunc_peer peer at which the path was truncated, or NULL if not
143 * @param get_path peers on reply path (or NULL if not recorded)
144 * @param get_path_length number of entries in get_path
145 * @param put_path peers on the PUT path (or NULL if not recorded)
146 * @param put_path_length number of entries in get_path
147 * @param type type of the result
148 * @param size number of bytes in data
149 * @param data pointer to the result data
150 */
151static void
152get_result_iterator (void *cls,
153 struct GNUNET_TIME_Absolute exp,
154 const struct GNUNET_HashCode *key,
155 const struct GNUNET_PeerIdentity *trunc_peer,
156 const struct GNUNET_DHT_PathElement *get_path,
157 unsigned int get_path_length,
158 const struct GNUNET_DHT_PathElement *put_path,
159 unsigned int put_path_length,
160 enum GNUNET_BLOCK_Type type,
161 size_t size,
162 const void *data)
163{
164 fprintf (stdout,
165 (GNUNET_BLOCK_TYPE_TEST == type)
166 ? _ ("Result %d, type %d:\n%.*s\n")
167 : _ ("Result %d, type %d:\n"),
168 result_count,
169 type,
170 (int) size,
171 (char *) data);
172 if (record_route && verbose)
173 {
174 {
175 struct GNUNET_PeerIdentity my_identity;
176
177 GNUNET_break (GNUNET_OK ==
178 GNUNET_CRYPTO_get_peer_identity (cfg,
179 &my_identity));
180 GNUNET_break (0 ==
181 GNUNET_DHT_verify_path (data,
182 size,
183 exp,
184 trunc_peer,
185 put_path,
186 put_path_length,
187 get_path,
188 get_path_length,
189 &my_identity));
190 }
191 fprintf (stdout,
192 " GET path: ");
193 for (unsigned int i = 0; i < get_path_length; i++)
194 fprintf (stdout,
195 "%s%s",
196 (0 == i) ? "" : "-",
197 GNUNET_i2s (&get_path[i].pred));
198 fprintf (stdout,
199 "\n PUT path: ");
200 for (unsigned int i = 0; i < put_path_length; i++)
201 fprintf (stdout,
202 "%s%s",
203 (0 == i) ? "" : "-",
204 GNUNET_i2s (&put_path[i].pred));
205 if (NULL != trunc_peer)
206 fprintf (stdout,
207 "!%s",
208 GNUNET_i2s (trunc_peer));
209 fprintf (stdout,
210 "\n");
211 }
212 result_count++;
213}
214
215
216/**
217 * Main function that will be run by the scheduler.
218 *
219 * @param cls closure
220 * @param args remaining command-line arguments
221 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
222 * @param c configuration
223 */
224static void
225run (void *cls,
226 char *const *args,
227 const char *cfgfile,
228 const struct GNUNET_CONFIGURATION_Handle *c)
229{
230 struct GNUNET_HashCode key;
231 enum GNUNET_DHT_RouteOption ro;
232
233 cfg = c;
234 if (NULL == query_key)
235 {
236 fprintf (stderr,
237 "%s",
238 _ ("Must provide key for DHT GET!\n"));
239 ret = 1;
240 return;
241 }
242 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
243 {
244 fprintf (stderr,
245 "%s",
246 _ ("Failed to connect to DHT service!\n"));
247 ret = 1;
248 return;
249 }
250 if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */
251 query_type = GNUNET_BLOCK_TYPE_TEST;
252 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
253 if (verbose)
254 fprintf (stderr,
255 "%s `%s' \n",
256 _ ("Issuing DHT GET with key"),
257 GNUNET_h2s_full (&key));
258 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
259 tt = GNUNET_SCHEDULER_add_delayed (timeout_request, &timeout_task, NULL);
260 ro = GNUNET_DHT_RO_NONE;
261 if (demultixplex_everywhere)
262 ro |= GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
263 if (record_route)
264 ro |= GNUNET_DHT_RO_RECORD_ROUTE;
265 get_handle = GNUNET_DHT_get_start (dht_handle,
266 query_type,
267 &key,
268 replication,
269 ro,
270 NULL,
271 0,
272 &get_result_iterator,
273 NULL);
274}
275
276
277/**
278 * Entry point for gnunet-dht-get
279 *
280 * @param argc number of arguments from the command line
281 * @param argv command line arguments
282 * @return 0 ok, 1 on error
283 */
284int
285main (int argc, char *const *argv)
286{
287 char *u8_argv = NULL;
288 struct GNUNET_GETOPT_CommandLineOption options[] = {
289 GNUNET_GETOPT_option_string (
290 'k',
291 "key",
292 "KEY",
293 gettext_noop ("the query key"),
294 &query_key),
295 GNUNET_GETOPT_option_uint (
296 'r',
297 "replication",
298 "LEVEL",
299 gettext_noop ("how many parallel requests (replicas) to create"),
300 &replication),
301 GNUNET_GETOPT_option_flag (
302 'R',
303 "record",
304 gettext_noop ("use DHT's record route option"),
305 &record_route),
306 GNUNET_GETOPT_option_uint (
307 't',
308 "type",
309 "TYPE",
310 gettext_noop ("the type of data to look for"),
311 &query_type),
312 GNUNET_GETOPT_option_relative_time (
313 'T',
314 "timeout",
315 "TIMEOUT",
316 gettext_noop ("how long to execute this query before giving up?"),
317 &timeout_request),
318 GNUNET_GETOPT_option_flag (
319 'x',
320 "demultiplex",
321 gettext_noop (
322 "use DHT's demultiplex everywhere option"),
323 &demultixplex_everywhere),
324 GNUNET_GETOPT_option_verbose (&verbose),
325 GNUNET_GETOPT_OPTION_END
326 };
327
328
329 if (GNUNET_OK !=
330 GNUNET_STRINGS_get_utf8_args (argc, argv,
331 &argc, &argv))
332 return 2;
333 ret = (GNUNET_OK ==
334 GNUNET_PROGRAM_run (
335 argc,
336 argv,
337 "gnunet-dht-get",
338 gettext_noop (
339 "Issue a GET request to the GNUnet DHT, prints results."),
340 options,
341 &run,
342 NULL))
343 ? ret
344 : 1;
345 // This is ugly, but meh. The GNUNET_STRINGS_get_utf8_args allows us to do this.
346 u8_argv = (char*) argv;
347 GNUNET_free (u8_argv);
348 return ret;
349}
350
351
352/* end of gnunet-dht-get.c */
diff --git a/src/cli/dht/gnunet-dht-hello.c b/src/cli/dht/gnunet-dht-hello.c
new file mode 100644
index 000000000..369ed5643
--- /dev/null
+++ b/src/cli/dht/gnunet-dht-hello.c
@@ -0,0 +1,178 @@
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 dht/gnunet-dht-hello.c
22 * @brief Obtain HELLO from DHT for bootstrapping
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_dht_service.h"
27
28#define LOG(kind, ...) GNUNET_log_from (kind, "dht-clients", __VA_ARGS__)
29
30/**
31 * Handle to the DHT
32 */
33static struct GNUNET_DHT_Handle *dht_handle;
34
35/**
36 * Handle to the DHT hello get operation.
37 */
38static struct GNUNET_DHT_HelloGetHandle *get_hello_handle;
39
40/**
41 * Global status value
42 */
43static int global_ret;
44
45
46/**
47 * Task run to clean up on shutdown.
48 *
49 * @param cls unused
50 */
51static void
52cleanup_task (void *cls)
53{
54 if (NULL != get_hello_handle)
55 {
56 GNUNET_DHT_hello_get_cancel (get_hello_handle);
57 get_hello_handle = NULL;
58 }
59 if (NULL != dht_handle)
60 {
61 GNUNET_DHT_disconnect (dht_handle);
62 dht_handle = NULL;
63 }
64}
65
66
67/**
68 * Task run when we are finished. Triggers shutdown.
69 *
70 * @param cls unused
71 */
72static void
73hello_done_cb (void *cls)
74{
75 GNUNET_SCHEDULER_shutdown ();
76}
77
78
79/**
80 * Function called on our HELLO.
81 *
82 * @param cls closure
83 * @param url the HELLO URL
84 */
85static void
86hello_result_cb (void *cls,
87 const char *url)
88{
89 get_hello_handle = NULL;
90 fprintf (stdout,
91 "%s\n",
92 url);
93 GNUNET_SCHEDULER_shutdown ();
94}
95
96
97/**
98 * Main function that will be run by the scheduler.
99 *
100 * @param cls closure, NULL
101 * @param args remaining command-line arguments
102 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
103 * @param cfg configuration
104 */
105static void
106run (void *cls,
107 char *const *args,
108 const char *cfgfile,
109 const struct GNUNET_CONFIGURATION_Handle *cfg)
110{
111 (void) cls;
112 (void) cfgfile;
113 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
114 NULL);
115 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg,
116 1)))
117 {
118 fprintf (stderr,
119 _ ("Failed to connect to DHT service!\n"));
120 global_ret = EXIT_NOTCONFIGURED;
121 GNUNET_SCHEDULER_shutdown ();
122 return;
123 }
124 if (NULL == args[0])
125 {
126 get_hello_handle = GNUNET_DHT_hello_get (dht_handle,
127 &hello_result_cb,
128 NULL);
129 GNUNET_break (NULL != get_hello_handle);
130 }
131 else
132 {
133 GNUNET_DHT_hello_offer (dht_handle,
134 args[0],
135 &hello_done_cb,
136 NULL);
137 }
138}
139
140
141/**
142 * Entry point for gnunet-dht-hello
143 *
144 * @param argc number of arguments from the command line
145 * @param argv command line arguments
146 * @return 0 ok, 1 on error
147 */
148int
149main (int argc,
150 char *const *argv)
151{
152 struct GNUNET_GETOPT_CommandLineOption options[] = {
153 GNUNET_GETOPT_OPTION_END
154 };
155 enum GNUNET_GenericReturnValue iret;
156
157 if (GNUNET_OK !=
158 GNUNET_STRINGS_get_utf8_args (argc, argv,
159 &argc, &argv))
160 return 2;
161 iret = GNUNET_PROGRAM_run (
162 argc,
163 argv,
164 "gnunet-dht-hello [URL]",
165 gettext_noop (
166 "Obtain HELLO from DHT or provide HELLO to DHT for bootstrapping"),
167 options,
168 &run,
169 NULL);
170 if (GNUNET_SYSERR == iret)
171 return EXIT_FAILURE;
172 if (GNUNET_NO == iret)
173 return EXIT_SUCCESS;
174 return global_ret;
175}
176
177
178/* end of gnunet-dht-hello.c */
diff --git a/src/cli/dht/gnunet-dht-monitor.c b/src/cli/dht/gnunet-dht-monitor.c
new file mode 100644
index 000000000..93ea1284a
--- /dev/null
+++ b/src/cli/dht/gnunet-dht-monitor.c
@@ -0,0 +1,345 @@
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 dht/gnunet-dht-monitor.c
22 * @brief search for data in DHT
23 * @author Christian Grothoff
24 * @author Bartlomiej Polot
25 */
26#include "platform.h"
27#include "gnunet_dht_service.h"
28
29/**
30 * The type of the query
31 */
32static unsigned int block_type;
33
34/**
35 * The key to be monitored
36 */
37static char *query_key;
38
39/**
40 * User supplied timeout value (in seconds)
41 */
42static struct GNUNET_TIME_Relative timeout_request = { 60000 };
43
44/**
45 * Be verbose
46 */
47static int verbose;
48
49/**
50 * Handle to the DHT
51 */
52static struct GNUNET_DHT_Handle *dht_handle;
53
54/**
55 * Global handle of the configuration
56 */
57static const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59/**
60 * Handle for the get request
61 */
62static struct GNUNET_DHT_MonitorHandle *monitor_handle;
63
64/**
65 * Count of messages received
66 */
67static unsigned int result_count;
68
69/**
70 * Global status value
71 */
72static int ret;
73
74/**
75 * Task scheduled to handle timeout.
76 */
77static struct GNUNET_SCHEDULER_Task *tt;
78
79
80/**
81 * Stop monitoring request and start shutdown
82 *
83 * @param cls closure (unused)
84 */
85static void
86cleanup_task (void *cls)
87{
88 if (verbose)
89 fprintf (stderr, "%s", "Cleaning up!\n");
90 if (NULL != monitor_handle)
91 {
92 GNUNET_DHT_monitor_stop (monitor_handle);
93 monitor_handle = NULL;
94 }
95 if (NULL != dht_handle)
96 {
97 GNUNET_DHT_disconnect (dht_handle);
98 dht_handle = NULL;
99 }
100 if (NULL != tt)
101 {
102 GNUNET_SCHEDULER_cancel (tt);
103 tt = NULL;
104 }
105}
106
107
108/**
109 * We hit a timeout. Stop monitoring request and start shutdown
110 *
111 * @param cls closure (unused)
112 */
113static void
114timeout_task (void *cls)
115{
116 tt = NULL;
117 GNUNET_SCHEDULER_shutdown ();
118}
119
120
121/**
122 * Callback called on each GET request going through the DHT.
123 *
124 * @param cls Closure.
125 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
126 * @param type The type of data in the request.
127 * @param hop_count Hop count so far.
128 * @param desired_replication_level Desired replication level.
129 * @param key Key of the requested data.
130 */
131static void
132get_callback (void *cls,
133 enum GNUNET_DHT_RouteOption options,
134 enum GNUNET_BLOCK_Type type,
135 uint32_t hop_count,
136 uint32_t desired_replication_level,
137 const struct GNUNET_HashCode *key)
138{
139 fprintf (stdout,
140 "GET #%u: type %d, key `%s'\n",
141 result_count,
142 (int) type,
143 GNUNET_h2s_full (key));
144 result_count++;
145}
146
147
148/**
149 * Callback called on each GET reply going through the DHT.
150 *
151 * @param cls Closure.
152 * @param type The type of data in the result.
153 * @param trunc_peer peer where the path was truncated, or NULL if the path is complete
154 * @param get_path Peers on GET path (or NULL if not recorded).
155 * @param get_path_length number of entries in get_path.
156 * @param put_path peers on the PUT path (or NULL if not recorded).
157 * @param put_path_length number of entries in get_path.
158 * @param exp Expiration time of the data.
159 * @param key Key of the data.
160 * @param data Pointer to the result data.
161 * @param size Number of bytes in data.
162 */
163static void
164get_resp_callback (void *cls,
165 enum GNUNET_BLOCK_Type type,
166 const struct GNUNET_PeerIdentity *trunc_peer,
167 const struct GNUNET_DHT_PathElement *get_path,
168 unsigned int get_path_length,
169 const struct GNUNET_DHT_PathElement *put_path,
170 unsigned int put_path_length,
171 struct GNUNET_TIME_Absolute exp,
172 const struct GNUNET_HashCode *key,
173 const void *data,
174 size_t size)
175{
176 fprintf (stdout,
177 (GNUNET_BLOCK_TYPE_TEST == type)
178 ? "RESPONSE #%u (%s): type %d, key `%s', data `%.*s'\n"
179 : "RESPONSE #%u (%s): type %d, key `%s'\n",
180 result_count,
181 GNUNET_STRINGS_absolute_time_to_string (exp),
182 (int) type,
183 GNUNET_h2s_full (key),
184 (unsigned int) size,
185 (char *) data);
186 result_count++;
187}
188
189
190/**
191 * Callback called on each PUT request going through the DHT.
192 *
193 * @param cls Closure.
194 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
195 * @param type The type of data in the request.
196 * @param hop_count Hop count so far.
197 * @param trunc_peer peer where the path was truncated, or NULL if the path is complete
198 * @param path_length number of entries in path (or 0 if not recorded).
199 * @param path peers on the PUT path (or NULL if not recorded).
200 * @param desired_replication_level Desired replication level.
201 * @param exp Expiration time of the data.
202 * @param key Key under which data is to be stored.
203 * @param data Pointer to the data carried.
204 * @param size Number of bytes in data.
205 */
206static void
207put_callback (void *cls,
208 enum GNUNET_DHT_RouteOption options,
209 enum GNUNET_BLOCK_Type type,
210 uint32_t hop_count,
211 uint32_t desired_replication_level,
212 const struct GNUNET_PeerIdentity *trunc_peer,
213 unsigned int path_length,
214 const struct GNUNET_DHT_PathElement *path,
215 struct GNUNET_TIME_Absolute exp,
216 const struct GNUNET_HashCode *key,
217 const void *data,
218 size_t size)
219{
220 fprintf (stdout,
221 (GNUNET_BLOCK_TYPE_TEST == type)
222 ? "PUT %u (%s): type %d, key `%s', data `%.*s'\n"
223 : "PUT %u (%s): type %d, key `%s'\n",
224 result_count,
225 GNUNET_STRINGS_absolute_time_to_string (exp),
226 (int) type,
227 GNUNET_h2s_full (key),
228 (unsigned int) size,
229 (char *) data);
230 result_count++;
231}
232
233
234/**
235 * Main function that will be run by the scheduler.
236 *
237 * @param cls closure
238 * @param args remaining command-line arguments
239 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
240 * @param c configuration
241 */
242static void
243run (void *cls,
244 char *const *args,
245 const char *cfgfile,
246 const struct GNUNET_CONFIGURATION_Handle *c)
247{
248 struct GNUNET_HashCode *key;
249 struct GNUNET_HashCode hc;
250
251 cfg = c;
252
253 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
254 {
255 fprintf (stderr, "%s", _ ("Failed to connect to DHT service!\n"));
256 ret = 1;
257 return;
258 }
259 if (GNUNET_BLOCK_TYPE_ANY == block_type) /* Type of data not set */
260 block_type = GNUNET_BLOCK_TYPE_TEST;
261 if (NULL != query_key)
262 {
263 key = &hc;
264 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (query_key, key))
265 GNUNET_CRYPTO_hash (query_key, strlen (query_key), key);
266 }
267 else
268 {
269 key = NULL;
270 }
271 if (verbose)
272 fprintf (stderr,
273 "Monitoring for %s\n",
274 GNUNET_STRINGS_relative_time_to_string (timeout_request,
275 GNUNET_NO));
276 tt = GNUNET_SCHEDULER_add_delayed (timeout_request, &timeout_task, NULL);
277 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
278 monitor_handle = GNUNET_DHT_monitor_start (dht_handle,
279 block_type,
280 key,
281 &get_callback,
282 &get_resp_callback,
283 &put_callback,
284 NULL);
285}
286
287
288/**
289 * Entry point for gnunet-dht-monitor
290 *
291 * @param argc number of arguments from the command line
292 * @param argv command line arguments
293 * @return 0 ok, 1 on error
294 */
295int
296main (int argc, char *const *argv)
297{
298 struct GNUNET_GETOPT_CommandLineOption options[] = {
299 GNUNET_GETOPT_option_string ('k',
300 "key",
301 "KEY",
302 gettext_noop ("the query key"),
303 &query_key),
304
305 GNUNET_GETOPT_option_uint ('t',
306 "type",
307 "TYPE",
308 gettext_noop ("the type of data to look for"),
309 &block_type),
310
311 GNUNET_GETOPT_option_relative_time (
312 'T',
313 "timeout",
314 "TIMEOUT",
315 gettext_noop ("how long should the monitor command run"),
316 &timeout_request),
317
318 GNUNET_GETOPT_option_flag ('V',
319 "verbose",
320 gettext_noop (
321 "be verbose (print progress information)"),
322 &verbose),
323
324 GNUNET_GETOPT_OPTION_END
325 };
326
327
328 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
329 return 2;
330
331 return (GNUNET_OK ==
332 GNUNET_PROGRAM_run (argc,
333 argv,
334 "gnunet-dht-monitor",
335 gettext_noop (
336 "Prints all packets that go through the DHT."),
337 options,
338 &run,
339 NULL))
340 ? ret
341 : 1;
342}
343
344
345/* end of gnunet-dht-monitor.c */
diff --git a/src/cli/dht/gnunet-dht-put.c b/src/cli/dht/gnunet-dht-put.c
new file mode 100644
index 000000000..8f8e098e4
--- /dev/null
+++ b/src/cli/dht/gnunet-dht-put.c
@@ -0,0 +1,255 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2017 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 dht/gnunet-dht-put.c
22 * @brief search for data in DHT
23 * @author Christian Grothoff
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_dht_service.h"
28
29/**
30 * The type of the query
31 */
32static unsigned int query_type;
33
34/**
35 * The key used in the DHT
36 */
37struct GNUNET_HashCode key;
38
39/**
40 * The key for the query
41 */
42static char *query_key;
43
44/**
45 * User supplied expiration value
46 */
47static struct GNUNET_TIME_Relative expiration;
48
49/**
50 * Desired replication level.
51 */
52static unsigned int replication = 5;
53
54/**
55 * Be verbose
56 */
57static unsigned int verbose;
58
59/**
60 * Use #GNUNET_DHT_DEMULTIPLEX_EVERYWHERE.
61 */
62static int demultixplex_everywhere;
63
64/**
65 * Use #GNUNET_DHT_RO_RECORD_ROUTE.
66 */
67static int record_route;
68
69/**
70 * Handle to the DHT
71 */
72static struct GNUNET_DHT_Handle *dht_handle;
73
74
75/**
76 * Global handle of the configuration
77 */
78static const struct GNUNET_CONFIGURATION_Handle *cfg;
79
80/**
81 * Global status value
82 */
83static int ret;
84
85/**
86 * The data to insert into the dht
87 */
88static char *data;
89
90
91static void
92shutdown_task (void *cls)
93{
94 if (NULL != dht_handle)
95 {
96 GNUNET_DHT_disconnect (dht_handle);
97 dht_handle = NULL;
98 }
99}
100
101
102/**
103 * Signature of the main function of a task.
104 *
105 * @param cls closure
106 */
107static void
108message_sent_cont (void *cls)
109{
110 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
111}
112
113
114/**
115 * Main function that will be run by the scheduler.
116 *
117 * @param cls closure
118 * @param args remaining command-line arguments
119 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
120 * @param c configuration
121 */
122static void
123run (void *cls,
124 char *const *args,
125 const char *cfgfile,
126 const struct GNUNET_CONFIGURATION_Handle *c)
127{
128 enum GNUNET_DHT_RouteOption ro;
129
130 cfg = c;
131 if ((NULL == query_key) || (NULL == data))
132 {
133 fprintf (stderr, "%s", _ ("Must provide KEY and DATA for DHT put!\n"));
134 ret = 1;
135 return;
136 }
137
138 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
139 {
140 fprintf (stderr, _ ("Could not connect to DHT service!\n"));
141 ret = 1;
142 return;
143 }
144 if (GNUNET_BLOCK_TYPE_ANY == query_type) /* Type of data not set */
145 query_type = GNUNET_BLOCK_TYPE_TEST;
146
147 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
148
149 if (verbose)
150 fprintf (stderr,
151 _ ("Issuing put request for `%s' with data `%s'!\n"),
152 query_key,
153 data);
154 ro = GNUNET_DHT_RO_NONE;
155 if (demultixplex_everywhere)
156 ro |= GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
157 if (record_route)
158 ro |= GNUNET_DHT_RO_RECORD_ROUTE;
159 GNUNET_DHT_put (dht_handle,
160 &key,
161 replication,
162 ro,
163 query_type,
164 strlen (data),
165 data,
166 GNUNET_TIME_relative_to_absolute (expiration),
167 &message_sent_cont,
168 NULL);
169}
170
171
172/**
173 * Entry point for gnunet-dht-put
174 *
175 * @param argc number of arguments from the command line
176 * @param argv command line arguments
177 * @return 0 ok, 1 on error
178 */
179int
180main (int argc, char *const *argv)
181{
182 char *u8_argv = NULL;
183 struct GNUNET_GETOPT_CommandLineOption options[] = {
184 GNUNET_GETOPT_option_string (
185 'd',
186 "data",
187 "DATA",
188 gettext_noop (
189 "the data to insert under the key"),
190 &data),
191 GNUNET_GETOPT_option_relative_time (
192 'e',
193 "expiration",
194 "EXPIRATION",
195 gettext_noop ("how long to store this entry in the dht (in seconds)"),
196 &expiration),
197 GNUNET_GETOPT_option_string (
198 'k',
199 "key",
200 "KEY",
201 gettext_noop ("the query key"),
202 &query_key),
203 GNUNET_GETOPT_option_flag (
204 'x',
205 "demultiplex",
206 gettext_noop (
207 "use DHT's demultiplex everywhere option"),
208 &demultixplex_everywhere),
209 GNUNET_GETOPT_option_uint (
210 'r',
211 "replication",
212 "LEVEL",
213 gettext_noop ("how many replicas to create"),
214 &replication),
215 GNUNET_GETOPT_option_flag (
216 'R',
217 "record",
218 gettext_noop ("use DHT's record route option"),
219 &record_route),
220 GNUNET_GETOPT_option_uint (
221 't',
222 "type",
223 "TYPE",
224 gettext_noop ("the type to insert data as"),
225 &query_type),
226 GNUNET_GETOPT_option_verbose (&verbose),
227 GNUNET_GETOPT_OPTION_END
228 };
229
230
231 if (GNUNET_OK !=
232 GNUNET_STRINGS_get_utf8_args (argc, argv,
233 &argc, &argv))
234 return 2;
235 expiration = GNUNET_TIME_UNIT_HOURS;
236 ret = (GNUNET_OK ==
237 GNUNET_PROGRAM_run (
238 argc,
239 argv,
240 "gnunet-dht-put",
241 gettext_noop (
242 "Issue a PUT request to the GNUnet DHT insert DATA under KEY."),
243 options,
244 &run,
245 NULL))
246 ? ret
247 : 1;
248 // This is ugly, but meh. The GNUNET_STRINGS_get_utf8_args allows us to do this.
249 u8_argv = (char*) argv;
250 GNUNET_free (u8_argv);
251 return ret;
252}
253
254
255/* end of gnunet-dht-put.c */
diff --git a/src/cli/dht/meson.build b/src/cli/dht/meson.build
new file mode 100644
index 000000000..d8c326513
--- /dev/null
+++ b/src/cli/dht/meson.build
@@ -0,0 +1,25 @@
1executable ('gnunet-dht-put',
2 ['gnunet-dht-put.c'],
3 dependencies: [libgnunetdht_dep, libgnunetutil_dep],
4 include_directories: [incdir, configuration_inc],
5 install: true,
6 install_dir: get_option('bindir'))
7executable ('gnunet-dht-get',
8 ['gnunet-dht-get.c'],
9 dependencies: [libgnunetdht_dep, libgnunetutil_dep],
10 include_directories: [incdir, configuration_inc],
11 install: true,
12 install_dir: get_option('bindir'))
13executable ('gnunet-dht-monitor',
14 ['gnunet-dht-monitor.c'],
15 dependencies: [libgnunetdht_dep, libgnunetutil_dep],
16 include_directories: [incdir, configuration_inc],
17 install: true,
18 install_dir: get_option('bindir'))
19executable ('gnunet-dht-hello',
20 ['gnunet-dht-hello.c'],
21 dependencies: [libgnunetdht_dep, libgnunetutil_dep],
22 include_directories: [incdir, configuration_inc],
23 install: true,
24 install_dir: get_option('bindir'))
25
diff --git a/src/cli/fs/.gitignore b/src/cli/fs/.gitignore
new file mode 100644
index 000000000..3ca8908d0
--- /dev/null
+++ b/src/cli/fs/.gitignore
@@ -0,0 +1,8 @@
1gnunet-unindex
2gnunet-auto-share
3gnunet-directory
4gnunet-download
5gnunet-fs
6gnunet-publish
7gnunet-search
8
diff --git a/src/cli/fs/Makefile.am b/src/cli/fs/Makefile.am
new file mode 100644
index 000000000..0d489dbe6
--- /dev/null
+++ b/src/cli/fs/Makefile.am
@@ -0,0 +1,107 @@
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
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13bin_PROGRAMS = \
14 gnunet-auto-share \
15 gnunet-directory \
16 gnunet-download \
17 gnunet-publish \
18 gnunet-search \
19 gnunet-fs \
20 gnunet-unindex
21
22gnunet_directory_SOURCES = \
23 gnunet-directory.c
24gnunet_directory_LDADD = \
25 $(top_builddir)/src/service/fs/libgnunetfs.la \
26 $(top_builddir)/src/lib/util/libgnunetutil.la \
27 $(GN_LIBINTL)
28
29if HAVE_LIBEXTRACTOR
30gnunet_directory_LDADD += \
31 -lextractor
32endif
33
34gnunet_fs_SOURCES = \
35 gnunet-fs.c
36gnunet_fs_LDADD = \
37 $(top_builddir)/src/service/fs/libgnunetfs.la \
38 $(top_builddir)/src/lib/util/libgnunetutil.la \
39 $(GN_LIBINTL)
40
41if HAVE_LIBEXTRACTOR
42gnunet_fs_LDADD += \
43 -lextractor
44endif
45
46gnunet_download_SOURCES = \
47 gnunet-download.c
48gnunet_download_LDADD = \
49 $(top_builddir)/src/service/fs/libgnunetfs.la \
50 $(top_builddir)/src/lib/util/libgnunetutil.la \
51 $(GN_LIBINTL)
52
53gnunet_publish_SOURCES = \
54 gnunet-publish.c
55gnunet_publish_LDADD = \
56 $(top_builddir)/src/service/identity/libgnunetidentity.la \
57 $(top_builddir)/src/service/fs/libgnunetfs.la \
58 $(top_builddir)/src/lib/util/libgnunetutil.la \
59 $(GN_LIBINTL)
60
61if HAVE_LIBEXTRACTOR
62gnunet_publish_LDADD += \
63 -lextractor
64endif
65
66gnunet_auto_share_SOURCES = \
67 gnunet-auto-share.c
68gnunet_auto_share_LDADD = \
69 $(top_builddir)/src/lib/util/libgnunetutil.la \
70 $(GN_LIBINTL)
71
72if HAVE_LIBEXTRACTOR
73gnunet_auto_share_LDADD += \
74 -lextractor
75endif
76
77gnunet_helper_fs_publish_SOURCES = \
78 gnunet-helper-fs-publish.c
79gnunet_helper_fs_publish_LDADD = \
80 $(top_builddir)/src/service/fs/libgnunetfs.la \
81 $(top_builddir)/src/lib/util/libgnunetutil.la \
82 $(GN_LIBINTL)
83
84if HAVE_LIBEXTRACTOR
85gnunet_helper_fs_publish_LDADD += \
86 -lextractor
87endif
88
89gnunet_search_SOURCES = \
90 gnunet-search.c
91gnunet_search_LDADD = \
92 $(top_builddir)/src/service/fs/libgnunetfs.la \
93 $(top_builddir)/src/lib/util/libgnunetutil.la \
94 $(GN_LIBINTL)
95
96if HAVE_LIBEXTRACTOR
97gnunet_search_LDADD += \
98 -lextractor
99endif
100
101
102gnunet_unindex_SOURCES = \
103 gnunet-unindex.c
104gnunet_unindex_LDADD = \
105 $(top_builddir)/src/service/fs/libgnunetfs.la \
106 $(top_builddir)/src/lib/util/libgnunetutil.la \
107 $(GN_LIBINTL)
diff --git a/src/cli/fs/gnunet-auto-share.c b/src/cli/fs/gnunet-auto-share.c
new file mode 100644
index 000000000..f91e9d00d
--- /dev/null
+++ b/src/cli/fs/gnunet-auto-share.c
@@ -0,0 +1,791 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--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 fs/gnunet-auto-share.c
22 * @brief automatically publish files on GNUnet
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - support loading meta data / keywords from resource file
27 * - add stability timer (a la buildbot)
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31
32#define MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
33
34#define MIN_DELAY GNUNET_TIME_UNIT_MINUTES
35
36
37/**
38 * Item in our work queue (or in the set of files/directories
39 * we have successfully published).
40 */
41struct WorkItem
42{
43 /**
44 * PENDING Work is kept in a linked list.
45 */
46 struct WorkItem *prev;
47
48 /**
49 * PENDING Work is kept in a linked list.
50 */
51 struct WorkItem *next;
52
53 /**
54 * Filename of the work item.
55 */
56 char *filename;
57
58 /**
59 * Unique identity for this work item (used to detect
60 * if we need to do the work again).
61 */
62 struct GNUNET_HashCode id;
63};
64
65
66/**
67 * Global return value from 'main'.
68 */
69static int ret;
70
71/**
72 * Are we running 'verbosely'?
73 */
74static unsigned int verbose;
75
76/**
77 * Configuration to use.
78 */
79static const struct GNUNET_CONFIGURATION_Handle *cfg;
80
81/**
82 * Name of the configuration file.
83 */
84static char *cfg_filename;
85
86/**
87 * Disable extractor option to use for publishing.
88 */
89static int disable_extractor;
90
91/**
92 * Disable creation time option to use for publishing.
93 */
94static int do_disable_creation_time;
95
96/**
97 * Handle for the main task that does scanning and working.
98 */
99static struct GNUNET_SCHEDULER_Task *run_task;
100
101/**
102 * Anonymity level option to use for publishing.
103 */
104static unsigned int anonymity_level = 1;
105
106/**
107 * Content priority option to use for publishing.
108 */
109static unsigned int content_priority = 365;
110
111/**
112 * Replication level option to use for publishing.
113 */
114static unsigned int replication_level = 1;
115
116/**
117 * Top-level directory we monitor to auto-publish.
118 */
119static const char *dir_name;
120
121/**
122 * Head of linked list of files still to publish.
123 */
124static struct WorkItem *work_head;
125
126/**
127 * Tail of linked list of files still to publish.
128 */
129static struct WorkItem *work_tail;
130
131/**
132 * Map from the hash of the filename (!) to a `struct WorkItem`
133 * that was finished.
134 */
135static struct GNUNET_CONTAINER_MultiHashMap *work_finished;
136
137/**
138 * Set to #GNUNET_YES if we are shutting down.
139 */
140static int do_shutdown;
141
142/**
143 * Start time of the current round; used to determine how long
144 * one iteration takes (which influences how fast we schedule
145 * the next one).
146 */
147static struct GNUNET_TIME_Absolute start_time;
148
149/**
150 * Pipe used to communicate 'gnunet-publish' completion (SIGCHLD) via signal.
151 */
152static struct GNUNET_DISK_PipeHandle *sigpipe;
153
154/**
155 * Handle to the 'gnunet-publish' process that we executed.
156 */
157static struct GNUNET_OS_Process *publish_proc;
158
159
160/**
161 * Compute the name of the state database file we will use.
162 */
163static char *
164get_state_file ()
165{
166 char *ret;
167
168 GNUNET_asprintf (&ret,
169 "%s%s.auto-share",
170 dir_name,
171 (DIR_SEPARATOR == dir_name[strlen (dir_name) - 1])
172 ? ""
173 : DIR_SEPARATOR_STR);
174 return ret;
175}
176
177
178/**
179 * Load the set of #work_finished items from disk.
180 */
181static void
182load_state ()
183{
184 char *fn;
185 struct GNUNET_BIO_ReadHandle *rh;
186 uint32_t n;
187 struct GNUNET_HashCode id;
188 struct WorkItem *wi;
189 char *emsg;
190
191 emsg = NULL;
192 fn = get_state_file ();
193 rh = GNUNET_BIO_read_open_file (fn);
194 GNUNET_free (fn);
195 if (NULL == rh)
196 return;
197 fn = NULL;
198 if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "number of files",
199 (int32_t *) &n))
200 goto error;
201 while (n-- > 0)
202 {
203 struct GNUNET_BIO_ReadSpec rs[] = {
204 GNUNET_BIO_read_spec_string ("filename", &fn, 1024),
205 GNUNET_BIO_read_spec_object ("id", &id, sizeof(struct GNUNET_HashCode)),
206 GNUNET_BIO_read_spec_end (),
207 };
208 if (GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs))
209 goto error;
210 wi = GNUNET_new (struct WorkItem);
211 wi->id = id;
212 wi->filename = fn;
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Loaded serialization ID for `%s' is `%s'\n",
215 wi->filename,
216 GNUNET_h2s (&id));
217 fn = NULL;
218 GNUNET_CRYPTO_hash (wi->filename, strlen (wi->filename), &id);
219 GNUNET_break (GNUNET_OK ==
220 GNUNET_CONTAINER_multihashmap_put (
221 work_finished,
222 &id,
223 wi,
224 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
225 }
226 if (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg))
227 return;
228 rh = NULL;
229error:
230 GNUNET_free (fn);
231 if (NULL != rh)
232 (void) GNUNET_BIO_read_close (rh, &emsg);
233 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
234 _ ("Failed to load state: %s\n"),
235 emsg);
236 GNUNET_free (emsg);
237}
238
239
240/**
241 * Write work item from the #work_finished map to the given write handle.
242 *
243 * @param cls the `struct GNUNET_BIO_WriteHandle *`
244 * @param key key of the item in the map (unused)
245 * @param value the `struct WorkItem` to write
246 * @return #GNUNET_OK to continue to iterate (if write worked)
247 */
248static int
249write_item (void *cls, const struct GNUNET_HashCode *key, void *value)
250{
251 struct GNUNET_BIO_WriteHandle *wh = cls;
252 struct WorkItem *wi = value;
253
254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255 "Saving serialization ID of file `%s' with value `%s'\n",
256 wi->filename,
257 GNUNET_h2s (&wi->id));
258 struct GNUNET_BIO_WriteSpec ws[] = {
259 GNUNET_BIO_write_spec_string ("auto-share-write-item-filename",
260 wi->filename),
261 GNUNET_BIO_write_spec_object ("id", &wi->id, sizeof(struct
262 GNUNET_HashCode)),
263 GNUNET_BIO_write_spec_end (),
264 };
265 if (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws))
266 return GNUNET_SYSERR; /* write error, abort iteration */
267 return GNUNET_OK;
268}
269
270
271/**
272 * Save the set of #work_finished items on disk.
273 */
274static void
275save_state ()
276{
277 uint32_t n;
278 struct GNUNET_BIO_WriteHandle *wh;
279 char *fn;
280
281 n = GNUNET_CONTAINER_multihashmap_size (work_finished);
282 fn = get_state_file ();
283 wh = GNUNET_BIO_write_open_file (fn);
284 if (NULL == wh)
285 {
286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
287 _ ("Failed to save state to file %s\n"),
288 fn);
289 GNUNET_free (fn);
290 return;
291 }
292 if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "size of state", n))
293 {
294 (void) GNUNET_BIO_write_close (wh, NULL);
295 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
296 _ ("Failed to save state to file %s\n"),
297 fn);
298 GNUNET_free (fn);
299 return;
300 }
301 (void) GNUNET_CONTAINER_multihashmap_iterate (work_finished, &write_item, wh);
302 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
303 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
304 _ ("Failed to save state to file %s\n"),
305 fn);
306 GNUNET_free (fn);
307}
308
309
310/**
311 * Task run on shutdown. Serializes our current state to disk.
312 *
313 * @param cls closure, unused
314 */
315static void
316do_stop_task (void *cls)
317{
318 do_shutdown = GNUNET_YES;
319 if (NULL != publish_proc)
320 {
321 GNUNET_OS_process_kill (publish_proc, SIGKILL);
322 return;
323 }
324 if (NULL != run_task)
325 {
326 GNUNET_SCHEDULER_cancel (run_task);
327 run_task = NULL;
328 }
329}
330
331
332/**
333 * Decide what the next task is (working or scanning) and schedule it.
334 */
335static void
336schedule_next_task (void);
337
338
339/**
340 * Task triggered whenever we receive a SIGCHLD (child
341 * process died).
342 *
343 * @param cls the `struct WorkItem` we were working on
344 */
345static void
346maint_child_death (void *cls)
347{
348 struct WorkItem *wi = cls;
349 struct GNUNET_HashCode key;
350 enum GNUNET_OS_ProcessStatusType type;
351 unsigned long code;
352 int ret;
353 char c;
354 const struct GNUNET_DISK_FileHandle *pr;
355 const struct GNUNET_SCHEDULER_TaskContext *tc;
356
357 run_task = NULL;
358 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
359 tc = GNUNET_SCHEDULER_get_task_context ();
360 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
361 {
362 /* shutdown scheduled us, someone else will kill child,
363 we should just try again */
364 run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
365 pr,
366 &maint_child_death,
367 wi);
368 return;
369 }
370 /* consume the signal */
371 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
372
373 ret = GNUNET_OS_process_status (publish_proc, &type, &code);
374 GNUNET_assert (GNUNET_SYSERR != ret);
375 if (GNUNET_NO == ret)
376 {
377 /* process still running? Then where did the SIGCHLD come from?
378 Well, let's declare it spurious (kernel bug?) and keep rolling.
379 */
380 GNUNET_break (0);
381 run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
382 pr,
383 &maint_child_death,
384 wi);
385 return;
386 }
387 GNUNET_assert (GNUNET_OK == ret);
388
389 GNUNET_OS_process_destroy (publish_proc);
390 publish_proc = NULL;
391
392 if (GNUNET_YES == do_shutdown)
393 {
394 GNUNET_free (wi->filename);
395 GNUNET_free (wi);
396 return;
397 }
398 if ((GNUNET_OS_PROCESS_EXITED == type) && (0 == code))
399 {
400 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
401 _ ("Publication of `%s' done\n"),
402 wi->filename);
403 GNUNET_CRYPTO_hash (wi->filename, strlen (wi->filename), &key);
404 GNUNET_break (GNUNET_OK ==
405 GNUNET_CONTAINER_multihashmap_put (
406 work_finished,
407 &key,
408 wi,
409 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
410 }
411 else
412 {
413 GNUNET_CONTAINER_DLL_insert_tail (work_head, work_tail, wi);
414 }
415 save_state ();
416 schedule_next_task ();
417}
418
419
420/**
421 * Signal handler called for SIGCHLD. Triggers the
422 * respective handler by writing to the trigger pipe.
423 */
424static void
425sighandler_child_death ()
426{
427 static char c;
428 int old_errno = errno; /* back-up errno */
429
430 GNUNET_break (
431 1 ==
432 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
433 GNUNET_DISK_PIPE_END_WRITE),
434 &c,
435 sizeof(c)));
436 errno = old_errno; /* restore errno */
437}
438
439
440/**
441 * Function called to process work items.
442 *
443 * @param cls closure, NULL
444 */
445static void
446work (void *cls)
447{
448 static char *argv[14];
449 static char anon_level[20];
450 static char content_prio[20];
451 static char repl_level[20];
452 struct WorkItem *wi;
453 const struct GNUNET_DISK_FileHandle *pr;
454 int argc;
455
456 run_task = NULL;
457 wi = work_head;
458 GNUNET_CONTAINER_DLL_remove (work_head, work_tail, wi);
459 argc = 0;
460 argv[argc++] = "gnunet-publish";
461 if (verbose)
462 argv[argc++] = "-V";
463 if (disable_extractor)
464 argv[argc++] = "-D";
465 if (do_disable_creation_time)
466 argv[argc++] = "-d";
467 argv[argc++] = "-c";
468 argv[argc++] = cfg_filename;
469 GNUNET_snprintf (anon_level, sizeof(anon_level), "%u", anonymity_level);
470 argv[argc++] = "-a";
471 argv[argc++] = anon_level;
472 GNUNET_snprintf (content_prio, sizeof(content_prio), "%u", content_priority);
473 argv[argc++] = "-p";
474 argv[argc++] = content_prio;
475 GNUNET_snprintf (repl_level, sizeof(repl_level), "%u", replication_level);
476 argv[argc++] = "-r";
477 argv[argc++] = repl_level;
478 argv[argc++] = wi->filename;
479 argv[argc] = NULL;
480 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Publishing `%s'\n"), wi->filename);
481 GNUNET_assert (NULL == publish_proc);
482 publish_proc = GNUNET_OS_start_process_vap (GNUNET_OS_USE_PIPE_CONTROL,
483 NULL,
484 NULL,
485 NULL,
486 "gnunet-publish",
487 argv);
488 if (NULL == publish_proc)
489 {
490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
491 _ ("Failed to run `%s'\n"),
492 "gnunet-publish");
493 GNUNET_CONTAINER_DLL_insert (work_head, work_tail, wi);
494 run_task =
495 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &work, NULL);
496 return;
497 }
498 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
499 run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
500 pr,
501 &maint_child_death,
502 wi);
503}
504
505
506/**
507 * Recursively scan the given file/directory structure to determine
508 * a unique ID that represents the current state of the hierarchy.
509 *
510 * @param cls where to store the unique ID we are computing
511 * @param filename file to scan
512 * @return #GNUNET_OK (always)
513 */
514static int
515determine_id (void *cls, const char *filename)
516{
517 struct GNUNET_HashCode *id = cls;
518 struct stat sbuf;
519 struct GNUNET_HashCode fx[2];
520 struct GNUNET_HashCode ft;
521
522 if (0 != stat (filename, &sbuf))
523 {
524 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
525 return GNUNET_OK;
526 }
527 GNUNET_CRYPTO_hash (filename, strlen (filename), &fx[0]);
528 if (! S_ISDIR (sbuf.st_mode))
529 {
530 uint64_t fattr[2];
531
532 fattr[0] = GNUNET_htonll (sbuf.st_size);
533 fattr[0] = GNUNET_htonll (sbuf.st_mtime);
534
535 GNUNET_CRYPTO_hash (fattr, sizeof(fattr), &fx[1]);
536 }
537 else
538 {
539 memset (&fx[1], 1, sizeof(struct GNUNET_HashCode));
540 GNUNET_DISK_directory_scan (filename, &determine_id, &fx[1]);
541 }
542 /* use hash here to make hierarchical structure distinct from
543 all files on the same level */
544 GNUNET_CRYPTO_hash (fx, sizeof(fx), &ft);
545 /* use XOR here so that order of the files in the directory
546 does not matter! */
547 GNUNET_CRYPTO_hash_xor (&ft, id, id);
548 return GNUNET_OK;
549}
550
551
552/**
553 * Function called with a filename (or directory name) to publish
554 * (if it has changed since the last time we published it). This function
555 * is called for the top-level files only.
556 *
557 * @param cls closure, NULL
558 * @param filename complete filename (absolute path)
559 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR during shutdown
560 */
561static int
562add_file (void *cls, const char *filename)
563{
564 struct WorkItem *wi;
565 struct GNUNET_HashCode key;
566 struct GNUNET_HashCode id;
567
568 if (GNUNET_YES == do_shutdown)
569 return GNUNET_SYSERR;
570 if ((NULL != strstr (filename, "/.auto-share")) ||
571 (NULL != strstr (filename, "\\.auto-share")))
572 return GNUNET_OK; /* skip internal file */
573 GNUNET_CRYPTO_hash (filename, strlen (filename), &key);
574 wi = GNUNET_CONTAINER_multihashmap_get (work_finished, &key);
575 memset (&id, 0, sizeof(struct GNUNET_HashCode));
576 determine_id (&id, filename);
577 if (NULL != wi)
578 {
579 if (0 == memcmp (&id, &wi->id, sizeof(struct GNUNET_HashCode)))
580 return GNUNET_OK; /* skip: we did this one already */
581 /* contents changed, need to re-do the directory... */
582 GNUNET_assert (
583 GNUNET_YES ==
584 GNUNET_CONTAINER_multihashmap_remove (work_finished, &key, wi));
585 }
586 else
587 {
588 wi = GNUNET_new (struct WorkItem);
589 wi->filename = GNUNET_strdup (filename);
590 }
591 wi->id = id;
592 GNUNET_CONTAINER_DLL_insert (work_head, work_tail, wi);
593 if (GNUNET_YES == do_shutdown)
594 return GNUNET_SYSERR;
595 return GNUNET_OK;
596}
597
598
599/**
600 * Periodically run task to update our view of the directory to share.
601 *
602 * @param cls NULL
603 */
604static void
605scan (void *cls)
606{
607 run_task = NULL;
608 start_time = GNUNET_TIME_absolute_get ();
609 (void) GNUNET_DISK_directory_scan (dir_name, &add_file, NULL);
610 schedule_next_task ();
611}
612
613
614/**
615 * Decide what the next task is (working or scanning) and schedule it.
616 */
617static void
618schedule_next_task ()
619{
620 struct GNUNET_TIME_Relative delay;
621
622 if (GNUNET_YES == do_shutdown)
623 return;
624 GNUNET_assert (NULL == run_task);
625 if (NULL == work_head)
626 {
627 /* delay by at most 4h, at least 1s, and otherwise in between depending
628 on how long it took to scan */
629 delay = GNUNET_TIME_absolute_get_duration (start_time);
630 delay = GNUNET_TIME_relative_saturating_multiply (delay, 100);
631 delay = GNUNET_TIME_relative_min (delay, MAX_DELAY);
632 delay = GNUNET_TIME_relative_max (delay, MIN_DELAY);
633 run_task = GNUNET_SCHEDULER_add_delayed (delay, &scan, NULL);
634 }
635 else
636 {
637 run_task = GNUNET_SCHEDULER_add_now (&work, NULL);
638 }
639}
640
641
642/**
643 * Main function that will be run by the scheduler.
644 *
645 * @param cls closure
646 * @param args remaining command-line arguments
647 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
648 * @param c configuration
649 */
650static void
651run (void *cls,
652 char *const *args,
653 const char *cfgfile,
654 const struct GNUNET_CONFIGURATION_Handle *c)
655{
656 /* check arguments */
657 if ((NULL == args[0]) || (NULL != args[1]) ||
658 (GNUNET_YES != GNUNET_DISK_directory_test (args[0], GNUNET_YES)))
659 {
660 printf (_ (
661 "You must specify one and only one directory name for automatic publication.\n"));
662 ret = -1;
663 return;
664 }
665 cfg_filename = GNUNET_strdup (cfgfile);
666 cfg = c;
667 dir_name = args[0];
668 work_finished = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO);
669 load_state ();
670 run_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
671 &scan,
672 NULL);
673 GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL);
674}
675
676
677/**
678 * Free memory associated with the work item from the work_finished map.
679 *
680 * @param cls NULL (unused)
681 * @param key key of the item in the map (unused)
682 * @param value the `struct WorkItem` to free
683 * @return #GNUNET_OK to continue to iterate
684 */
685static int
686free_item (void *cls, const struct GNUNET_HashCode *key, void *value)
687{
688 struct WorkItem *wi = value;
689
690 GNUNET_free (wi->filename);
691 GNUNET_free (wi);
692 return GNUNET_OK;
693}
694
695
696/**
697 * The main function to automatically publish content to GNUnet.
698 *
699 * @param argc number of arguments from the command line
700 * @param argv command line arguments
701 * @return 0 ok, 1 on error
702 */
703int
704main (int argc, char *const *argv)
705{
706 struct GNUNET_GETOPT_CommandLineOption options[] = {
707 GNUNET_GETOPT_option_uint ('a',
708 "anonymity",
709 "LEVEL",
710 gettext_noop (
711 "set the desired LEVEL of sender-anonymity"),
712 &anonymity_level),
713
714 GNUNET_GETOPT_option_flag (
715 'd',
716 "disable-creation-time",
717 gettext_noop (
718 "disable adding the creation time to the metadata of the uploaded file"),
719 &do_disable_creation_time),
720
721 GNUNET_GETOPT_option_flag (
722 'D',
723 "disable-extractor",
724 gettext_noop ("do not use libextractor to add keywords or metadata"),
725 &disable_extractor),
726
727 GNUNET_GETOPT_option_uint ('p',
728 "priority",
729 "PRIORITY",
730 gettext_noop (
731 "specify the priority of the content"),
732 &content_priority),
733
734 GNUNET_GETOPT_option_uint ('r',
735 "replication",
736 "LEVEL",
737 gettext_noop (
738 "set the desired replication LEVEL"),
739 &replication_level),
740
741 GNUNET_GETOPT_option_verbose (&verbose),
742
743 GNUNET_GETOPT_OPTION_END
744 };
745 struct WorkItem *wi;
746 int ok;
747 struct GNUNET_SIGNAL_Context *shc_chld;
748
749 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
750 return 2;
751 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
752 GNUNET_assert (NULL != sigpipe);
753 shc_chld =
754 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
755 ok =
756 (GNUNET_OK ==
757 GNUNET_PROGRAM_run (
758 argc,
759 argv,
760 "gnunet-auto-share [OPTIONS] FILENAME",
761 gettext_noop ("Automatically publish files from a directory on GNUnet"),
762 options,
763 &run,
764 NULL))
765 ? ret
766 : 1;
767 if (NULL != work_finished)
768 {
769 (void) GNUNET_CONTAINER_multihashmap_iterate (work_finished,
770 &free_item,
771 NULL);
772 GNUNET_CONTAINER_multihashmap_destroy (work_finished);
773 }
774 while (NULL != (wi = work_head))
775 {
776 GNUNET_CONTAINER_DLL_remove (work_head, work_tail, wi);
777 GNUNET_free (wi->filename);
778 GNUNET_free (wi);
779 }
780 GNUNET_SIGNAL_handler_uninstall (shc_chld);
781 shc_chld = NULL;
782 GNUNET_DISK_pipe_close (sigpipe);
783 sigpipe = NULL;
784 GNUNET_free (cfg_filename);
785 cfg_filename = NULL;
786 GNUNET_free_nz ((void *) argv);
787 return ok;
788}
789
790
791/* end of gnunet-auto-share.c */
diff --git a/src/cli/fs/gnunet-directory.c b/src/cli/fs/gnunet-directory.c
new file mode 100644
index 000000000..ab9f2905a
--- /dev/null
+++ b/src/cli/fs/gnunet-directory.c
@@ -0,0 +1,212 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 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 fs/gnunet-directory.c
22 * @brief display content of GNUnet directories
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26
27#include "gnunet_fs_service.h"
28
29static int ret;
30
31/**
32 * Print a meta data entry.
33 *
34 * @param cls closure (unused)
35 * @param plugin_name name of the plugin that generated the meta data
36 * @param type type of the keyword
37 * @param format format of data
38 * @param data_mime_type mime type of data
39 * @param data value of the meta data
40 * @param data_size number of bytes in @a data
41 * @return always 0 (to continue iterating)
42 */
43static int
44item_printer (void *cls,
45 const char *plugin_name,
46 enum EXTRACTOR_MetaType type,
47 enum EXTRACTOR_MetaFormat format,
48 const char *data_mime_type,
49 const char *data,
50 size_t data_size)
51{
52 if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA)
53 {
54 printf (_ ("\t<original file embedded in %u bytes of meta data>\n"),
55 (unsigned int) data_size);
56 return 0;
57 }
58 if ((format != EXTRACTOR_METAFORMAT_UTF8) &&
59 (format != EXTRACTOR_METAFORMAT_C_STRING))
60 return 0;
61 if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME)
62 return 0;
63#if HAVE_LIBEXTRACTOR
64 printf ("\t%20s: %s\n",
65 dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN,
66 EXTRACTOR_metatype_to_string (type)),
67 data);
68#else
69 printf ("\t%20d: %s\n", type, data);
70#endif
71 return 0;
72}
73
74
75/**
76 * Print an entry in a directory.
77 *
78 * @param cls closure (not used)
79 * @param filename name of the file in the directory
80 * @param uri URI of the file
81 * @param meta metadata for the file; metadata for
82 * the directory if everything else is NULL/zero
83 * @param length length of the available data for the file
84 * (of type size_t since data must certainly fit
85 * into memory; if files are larger than size_t
86 * permits, then they will certainly not be
87 * embedded with the directory itself).
88 * @param data data available for the file (length bytes)
89 */
90static void
91print_entry (void *cls,
92 const char *filename,
93 const struct GNUNET_FS_Uri *uri,
94 const struct GNUNET_FS_MetaData *meta,
95 size_t length,
96 const void *data)
97{
98 char *string;
99 char *name;
100
101 name = GNUNET_FS_meta_data_get_by_type (
102 meta,
103 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
104 if (uri == NULL)
105 {
106 printf (_ ("Directory `%s' meta data:\n"), name ? name : "");
107 GNUNET_FS_meta_data_iterate (meta, &item_printer, NULL);
108 printf ("\n");
109 printf (_ ("Directory `%s' contents:\n"), name ? name : "");
110 GNUNET_free (name);
111 return;
112 }
113 string = GNUNET_FS_uri_to_string (uri);
114 printf ("%s (%s):\n", name ? name : "", string);
115 GNUNET_free (string);
116 GNUNET_FS_meta_data_iterate (meta, &item_printer, NULL);
117 printf ("\n");
118 GNUNET_free (name);
119}
120
121
122/**
123 * Main function that will be run by the scheduler.
124 *
125 * @param cls closure
126 * @param args remaining command-line arguments
127 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
128 * @param cfg configuration
129 */
130static void
131run (void *cls,
132 char *const *args,
133 const char *cfgfile,
134 const struct GNUNET_CONFIGURATION_Handle *cfg)
135{
136 struct GNUNET_DISK_MapHandle *map;
137 struct GNUNET_DISK_FileHandle *h;
138 void *data;
139 size_t len;
140 uint64_t size;
141 const char *filename;
142 int i;
143
144 if (NULL == args[0])
145 {
146 fprintf (stderr, "%s", _ ("You must specify a filename to inspect.\n"));
147 ret = 1;
148 return;
149 }
150 i = 0;
151 while (NULL != (filename = args[i++]))
152 {
153 if ((GNUNET_OK !=
154 GNUNET_DISK_file_size (filename, &size, GNUNET_YES, GNUNET_YES)) ||
155 (NULL == (h = GNUNET_DISK_file_open (filename,
156 GNUNET_DISK_OPEN_READ,
157 GNUNET_DISK_PERM_NONE))))
158 {
159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
160 _ ("Failed to read directory `%s'\n"),
161 filename);
162 ret = 1;
163 continue;
164 }
165 len = (size_t) size;
166 data = GNUNET_DISK_file_map (h, &map, GNUNET_DISK_MAP_TYPE_READ, len);
167 GNUNET_assert (NULL != data);
168 if (GNUNET_OK !=
169 GNUNET_FS_directory_list_contents (len, data, 0, &print_entry, NULL))
170 fprintf (stdout, _ ("`%s' is not a GNUnet directory\n"), filename);
171 else
172 printf ("\n");
173 GNUNET_DISK_file_unmap (map);
174 GNUNET_DISK_file_close (h);
175 }
176}
177
178
179/**
180 * The main function to inspect GNUnet directories.
181 *
182 * @param argc number of arguments from the command line
183 * @param argv command line arguments
184 * @return 0 ok, 1 on error
185 */
186int
187main (int argc, char *const *argv)
188{
189 static struct GNUNET_GETOPT_CommandLineOption options[] = {
190 GNUNET_GETOPT_OPTION_END
191 };
192
193 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
194 return 2;
195
196 ret = (GNUNET_OK ==
197 GNUNET_PROGRAM_run (argc,
198 argv,
199 "gnunet-directory [OPTIONS] FILENAME",
200 gettext_noop (
201 "Display contents of a GNUnet directory"),
202 options,
203 &run,
204 NULL))
205 ? ret
206 : 1;
207 GNUNET_free_nz ((void *) argv);
208 return ret;
209}
210
211
212/* end of gnunet-directory.c */
diff --git a/src/cli/fs/gnunet-download.c b/src/cli/fs/gnunet-download.c
new file mode 100644
index 000000000..4694077e9
--- /dev/null
+++ b/src/cli/fs/gnunet-download.c
@@ -0,0 +1,385 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 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 fs/gnunet-download.c
22 * @brief downloading for files on GNUnet
23 * @author Christian Grothoff
24 * @author Krista Bennett
25 * @author James Blackwell
26 * @author Igor Wronsky
27 */
28#include "platform.h"
29
30#include "gnunet_fs_service.h"
31
32static int ret;
33
34static unsigned int verbose;
35
36static int delete_incomplete;
37
38static const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40static struct GNUNET_FS_Handle *ctx;
41
42static struct GNUNET_FS_DownloadContext *dc;
43
44static unsigned int anonymity = 1;
45
46static unsigned int parallelism = 16;
47
48static unsigned int request_parallelism = 4092;
49
50static int do_recursive;
51
52static char *filename;
53
54static int local_only;
55
56
57static void
58cleanup_task (void *cls)
59{
60 GNUNET_FS_stop (ctx);
61 ctx = NULL;
62}
63
64
65static void
66shutdown_task (void *cls)
67{
68 if (NULL != dc)
69 {
70 GNUNET_FS_download_stop (dc, delete_incomplete);
71 dc = NULL;
72 }
73}
74
75
76/**
77 * Display progress bar (if tty).
78 *
79 * @param x current position in the download
80 * @param n total size of the download
81 * @param w desired number of steps in the progress bar
82 */
83static void
84display_bar (unsigned long long x, unsigned long long n, unsigned int w)
85{
86 char buf[w + 20];
87 unsigned int p;
88 unsigned int endeq;
89 float ratio_complete;
90
91 if (0 == isatty (1))
92 return;
93 ratio_complete = x / (float) n;
94 endeq = ratio_complete * w;
95 GNUNET_snprintf (buf, sizeof(buf), "%3d%% [", (int) (ratio_complete * 100));
96 for (p = 0; p < endeq; p++)
97 strcat (buf, "=");
98 for (p = endeq; p < w; p++)
99 strcat (buf, " ");
100 strcat (buf, "]\r");
101 printf ("%s", buf);
102 fflush (stdout);
103}
104
105
106/**
107 * Called by FS client to give information about the progress of an
108 * operation.
109 *
110 * @param cls closure
111 * @param info details about the event, specifying the event type
112 * and various bits about the event
113 * @return client-context (for the next progress call
114 * for this operation; should be set to NULL for
115 * SUSPEND and STOPPED events). The value returned
116 * will be passed to future callbacks in the respective
117 * field in the `struct GNUNET_FS_ProgressInfo`
118 */
119static void *
120progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
121{
122 char *s;
123 const char *s2;
124 char *t;
125
126 switch (info->status)
127 {
128 case GNUNET_FS_STATUS_DOWNLOAD_START:
129 if (verbose > 1)
130 fprintf (stderr,
131 _ ("Starting download `%s'.\n"),
132 info->value.download.filename);
133 break;
134
135 case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
136 if (verbose)
137 {
138 s = GNUNET_strdup (
139 GNUNET_STRINGS_relative_time_to_string (info->value.download.eta,
140 GNUNET_YES));
141 if (info->value.download.specifics.progress.block_download_duration
142 .rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
143 s2 = _ ("<unknown time>");
144 else
145 s2 = GNUNET_STRINGS_relative_time_to_string (info->value.download
146 .specifics.progress
147 .block_download_duration,
148 GNUNET_YES);
149 t = GNUNET_STRINGS_byte_size_fancy (
150 info->value.download.completed * 1000LL
151 / (info->value.download.duration.rel_value_us + 1));
152 fprintf (
153 stdout,
154 _ (
155 "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"),
156 info->value.download.filename,
157 (unsigned long long) info->value.download.completed,
158 (unsigned long long) info->value.download.size,
159 s,
160 t,
161 s2);
162 GNUNET_free (s);
163 GNUNET_free (t);
164 }
165 else
166 {
167 display_bar (info->value.download.completed,
168 info->value.download.size,
169 60);
170 }
171 break;
172
173 case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
174 if (0 != isatty (1))
175 fprintf (stdout, "\n");
176 fprintf (stderr,
177 _ ("Error downloading: %s.\n"),
178 info->value.download.specifics.error.message);
179 GNUNET_SCHEDULER_shutdown ();
180 break;
181
182 case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
183 s = GNUNET_STRINGS_byte_size_fancy (
184 info->value.download.completed * 1000
185 / (info->value.download.duration.rel_value_us + 1));
186 if (0 != isatty (1))
187 fprintf (stdout, "\n");
188 fprintf (stdout,
189 _ ("Downloading `%s' done (%s/s).\n"),
190 info->value.download.filename,
191 s);
192 GNUNET_free (s);
193 if (info->value.download.dc == dc)
194 GNUNET_SCHEDULER_shutdown ();
195 break;
196
197 case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
198 if (info->value.download.dc == dc)
199 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
200 break;
201
202 case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
203 case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
204 break;
205
206 default:
207 fprintf (stderr, _ ("Unexpected status: %d\n"), info->status);
208 break;
209 }
210 return NULL;
211}
212
213
214/**
215 * Main function that will be run by the scheduler.
216 *
217 * @param cls closure
218 * @param args remaining command-line arguments
219 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
220 * @param c configuration
221 */
222static void
223run (void *cls,
224 char *const *args,
225 const char *cfgfile,
226 const struct GNUNET_CONFIGURATION_Handle *c)
227{
228 struct GNUNET_FS_Uri *uri;
229 char *emsg;
230 enum GNUNET_FS_DownloadOptions options;
231
232 if (NULL == args[0])
233 {
234 fprintf (stderr, "%s", _ ("You need to specify a URI argument.\n"));
235 return;
236 }
237 uri = GNUNET_FS_uri_parse (args[0], &emsg);
238 if (NULL == uri)
239 {
240 fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg);
241 GNUNET_free (emsg);
242 ret = 1;
243 return;
244 }
245 if ((! GNUNET_FS_uri_test_chk (uri)) && (! GNUNET_FS_uri_test_loc (uri)))
246 {
247 fprintf (stderr, "%s", _ ("Only CHK or LOC URIs supported.\n"));
248 ret = 1;
249 GNUNET_FS_uri_destroy (uri);
250 return;
251 }
252 if (NULL == filename)
253 {
254 fprintf (stderr, "%s", _ ("Target filename must be specified.\n"));
255 ret = 1;
256 GNUNET_FS_uri_destroy (uri);
257 return;
258 }
259 cfg = c;
260 ctx = GNUNET_FS_start (cfg,
261 "gnunet-download",
262 &progress_cb,
263 NULL,
264 GNUNET_FS_FLAGS_NONE,
265 GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM,
266 parallelism,
267 GNUNET_FS_OPTIONS_REQUEST_PARALLELISM,
268 request_parallelism,
269 GNUNET_FS_OPTIONS_END);
270 if (NULL == ctx)
271 {
272 fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
273 GNUNET_FS_uri_destroy (uri);
274 ret = 1;
275 return;
276 }
277 options = GNUNET_FS_DOWNLOAD_OPTION_NONE;
278 if (do_recursive)
279 options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
280 if (local_only)
281 options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY;
282 dc = GNUNET_FS_download_start (ctx,
283 uri,
284 NULL,
285 filename,
286 NULL,
287 0,
288 GNUNET_FS_uri_chk_get_file_size (uri),
289 anonymity,
290 options,
291 NULL,
292 NULL);
293 GNUNET_FS_uri_destroy (uri);
294 if (dc == NULL)
295 {
296 GNUNET_FS_stop (ctx);
297 ctx = NULL;
298 return;
299 }
300 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
301}
302
303
304/**
305 * The main function to download GNUnet.
306 *
307 * @param argc number of arguments from the command line
308 * @param argv command line arguments
309 * @return 0 ok, 1 on error
310 */
311int
312main (int argc, char *const *argv)
313{
314 struct GNUNET_GETOPT_CommandLineOption options[] =
315 { GNUNET_GETOPT_option_uint ('a',
316 "anonymity",
317 "LEVEL",
318 gettext_noop (
319 "set the desired LEVEL of receiver-anonymity"),
320 &anonymity),
321
322 GNUNET_GETOPT_option_flag (
323 'D',
324 "delete-incomplete",
325 gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
326 &delete_incomplete),
327
328 GNUNET_GETOPT_option_flag (
329 'n',
330 "no-network",
331 gettext_noop ("only search the local peer (no P2P network search)"),
332 &local_only),
333 GNUNET_GETOPT_option_string ('o',
334 "output",
335 "FILENAME",
336 gettext_noop ("write the file to FILENAME"),
337 &filename),
338 GNUNET_GETOPT_option_uint (
339 'p',
340 "parallelism",
341 "DOWNLOADS",
342 gettext_noop (
343 "set the maximum number of parallel downloads that is allowed"),
344 &parallelism),
345 GNUNET_GETOPT_option_uint (
346 'r',
347 "request-parallelism",
348 "REQUESTS",
349 gettext_noop (
350 "set the maximum number of parallel requests for blocks that is allowed"),
351 &request_parallelism),
352 GNUNET_GETOPT_option_flag ('R',
353 "recursive",
354 gettext_noop (
355 "download a GNUnet directory recursively"),
356 &do_recursive),
357 GNUNET_GETOPT_option_increment_uint (
358 'V',
359 "verbose",
360 gettext_noop ("be verbose (print progress information)"),
361 &verbose),
362 GNUNET_GETOPT_OPTION_END };
363
364 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
365 return 2;
366
367 ret =
368 (GNUNET_OK ==
369 GNUNET_PROGRAM_run (
370 argc,
371 argv,
372 "gnunet-download [OPTIONS] URI",
373 gettext_noop (
374 "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"),
375 options,
376 &run,
377 NULL))
378 ? ret
379 : 1;
380 GNUNET_free_nz ((void *) argv);
381 return ret;
382}
383
384
385/* end of gnunet-download.c */
diff --git a/src/cli/fs/gnunet-fs.c b/src/cli/fs/gnunet-fs.c
new file mode 100644
index 000000000..21e3c4a40
--- /dev/null
+++ b/src/cli/fs/gnunet-fs.c
@@ -0,0 +1,191 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 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 fs/gnunet-fs.c
22 * @brief special file-sharing functions
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26
27#include "gnunet_fs_service.h"
28
29/**
30 * Return value.
31 */
32static int ret;
33
34/**
35 * Handle to FS service.
36 */
37static struct GNUNET_FS_Handle *fs;
38
39/**
40 * Handle for the index listing operation.
41 */
42static struct GNUNET_FS_GetIndexedContext *gic;
43
44/**
45 * Option -i given?
46 */
47static int list_indexed_files;
48
49/**
50 * Option -v given?
51 */
52static unsigned int verbose;
53
54
55/**
56 * Print indexed filenames to stdout.
57 *
58 * @param cls closure
59 * @param filename the name of the file
60 * @param file_id hash of the contents of the indexed file
61 * @return #GNUNET_OK to continue iteration
62 */
63static enum GNUNET_GenericReturnValue
64print_indexed (void *cls,
65 const char *filename,
66 const struct GNUNET_HashCode *file_id)
67{
68 if (NULL == filename)
69 {
70 gic = NULL;
71 GNUNET_SCHEDULER_shutdown ();
72 return GNUNET_OK;
73 }
74 if (verbose)
75 fprintf (stdout,
76 "%s: %s\n",
77 GNUNET_h2s (file_id),
78 filename);
79 else
80 fprintf (stdout,
81 "%s\n",
82 filename);
83 return GNUNET_OK;
84}
85
86
87/**
88 * Function run on shutdown.
89 *
90 * @param cls NULL
91 */
92static void
93do_shutdown (void *cls)
94{
95 (void) cls;
96 if (NULL != gic)
97 {
98 GNUNET_FS_get_indexed_files_cancel (gic);
99 gic = NULL;
100 }
101 if (NULL != fs)
102 {
103 GNUNET_FS_stop (fs);
104 fs = NULL;
105 }
106}
107
108
109/**
110 * Main function that will be run by the scheduler.
111 *
112 * @param cls closure
113 * @param args remaining command-line arguments
114 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
115 * @param cfg configuration
116 */
117static void
118run (void *cls,
119 char *const *args,
120 const char *cfgfile,
121 const struct GNUNET_CONFIGURATION_Handle *cfg)
122{
123 if (! list_indexed_files)
124 return;
125 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
126 NULL);
127 fs = GNUNET_FS_start (cfg,
128 "gnunet-fs",
129 NULL,
130 NULL,
131 GNUNET_FS_FLAGS_NONE,
132 GNUNET_FS_OPTIONS_END);
133 if (NULL == fs)
134 {
135 ret = 1;
136 return;
137 }
138 gic = GNUNET_FS_get_indexed_files (fs,
139 &print_indexed,
140 NULL);
141 if (NULL == gic)
142 {
143 ret = 2;
144 GNUNET_SCHEDULER_shutdown ();
145 return;
146 }
147}
148
149
150/**
151 * The main function to access special file-sharing functions.
152 *
153 * @param argc number of arguments from the command line
154 * @param argv command line arguments
155 * @return 0 ok, 1 on error
156 */
157int
158main (int argc,
159 char *const *argv)
160{
161 struct GNUNET_GETOPT_CommandLineOption options[] = {
162 GNUNET_GETOPT_option_flag ('i',
163 "list-indexed",
164 gettext_noop (
165 "print a list of all indexed files"),
166 &list_indexed_files),
167
168 GNUNET_GETOPT_option_verbose (&verbose),
169 GNUNET_GETOPT_OPTION_END
170 };
171
172 if (GNUNET_OK !=
173 GNUNET_STRINGS_get_utf8_args (argc, argv,
174 &argc, &argv))
175 return 2;
176 ret = (GNUNET_OK ==
177 GNUNET_PROGRAM_run (argc,
178 argv,
179 "gnunet-fs [OPTIONS]",
180 gettext_noop ("Special file-sharing operations"),
181 options,
182 &run,
183 NULL))
184 ? ret
185 : 1;
186 GNUNET_free_nz ((void *) argv);
187 return ret;
188}
189
190
191/* end of gnunet-fs.c */
diff --git a/src/cli/fs/gnunet-publish.c b/src/cli/fs/gnunet-publish.c
new file mode 100644
index 000000000..7a87130de
--- /dev/null
+++ b/src/cli/fs/gnunet-publish.c
@@ -0,0 +1,1009 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 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 fs/gnunet-publish.c
22 * @brief publishing files on GNUnet
23 * @author Christian Grothoff
24 * @author Krista Bennett
25 * @author James Blackwell
26 * @author Igor Wronsky
27 */
28#include "platform.h"
29
30#include "gnunet_fs_service.h"
31#include "gnunet_identity_service.h"
32
33/**
34 * Global return value from #main().
35 */
36static int ret;
37
38/**
39 * Command line option 'verbose' set
40 */
41static unsigned int verbose;
42
43/**
44 * Handle to our configuration.
45 */
46static const struct GNUNET_CONFIGURATION_Handle *cfg;
47
48/**
49 * Handle for interaction with file-sharing service.
50 */
51static struct GNUNET_FS_Handle *ctx;
52
53/**
54 * Handle to FS-publishing operation.
55 */
56static struct GNUNET_FS_PublishContext *pc;
57
58/**
59 * Meta-data provided via command-line option.
60 */
61static struct GNUNET_FS_MetaData *meta;
62
63/**
64 * Keywords provided via command-line option.
65 */
66static struct GNUNET_FS_Uri *topKeywords;
67
68/**
69 * Options we set for published blocks.
70 */
71static struct GNUNET_FS_BlockOptions bo = { { 0LL }, 1, 365, 1 };
72
73/**
74 * Value of URI provided on command-line (when not publishing
75 * a file but just creating UBlocks to refer to an existing URI).
76 */
77static char *uri_string;
78
79/**
80 * Value of URI provided on command-line (when not publishing
81 * a file but just creating UBlocks to refer to an existing URI);
82 * parsed version of 'uri_string'.
83 */
84static struct GNUNET_FS_Uri *uri;
85
86/**
87 * Command-line option for namespace publishing: identifier for updates
88 * to this publication.
89 */
90static char *next_id;
91
92/**
93 * Command-line option for namespace publishing: identifier for this
94 * publication.
95 */
96static char *this_id;
97
98/**
99 * Command-line option identifying the pseudonym to use for the publication.
100 */
101static char *pseudonym;
102
103/**
104 * Command-line option for 'inserting'
105 */
106static int do_insert;
107
108/**
109 * Command-line option to disable meta data extraction.
110 */
111static int disable_extractor;
112
113/**
114 * Command-line option to merely simulate publishing operation.
115 */
116static int do_simulate;
117
118/**
119 * Command-line option to only perform meta data extraction, but not publish.
120 */
121static int extract_only;
122
123/**
124 * Command-line option to disable adding creation time.
125 */
126static int enable_creation_time;
127
128/**
129 * Handle to the directory scanner (for recursive insertions).
130 */
131static struct GNUNET_FS_DirScanner *ds;
132
133/**
134 * Which namespace do we publish to? NULL if we do not publish to
135 * a namespace.
136 */
137static struct GNUNET_IDENTITY_Ego *namespace;
138
139/**
140 * Handle to identity service.
141 */
142static struct GNUNET_IDENTITY_Handle *identity;
143
144
145/**
146 * We are finished with the publishing operation, clean up all
147 * FS state.
148 *
149 * @param cls NULL
150 */
151static void
152do_stop_task (void *cls)
153{
154 struct GNUNET_FS_PublishContext *p;
155
156 if (NULL != ds)
157 {
158 GNUNET_FS_directory_scan_abort (ds);
159 ds = NULL;
160 }
161 if (NULL != identity)
162 {
163 GNUNET_IDENTITY_disconnect (identity);
164 identity = NULL;
165 }
166 if (NULL != pc)
167 {
168 p = pc;
169 pc = NULL;
170 GNUNET_FS_publish_stop (p);
171 }
172 if (NULL != ctx)
173 {
174 GNUNET_FS_stop (ctx);
175 ctx = NULL;
176 }
177 if (NULL != meta)
178 {
179 GNUNET_FS_meta_data_destroy (meta);
180 meta = NULL;
181 }
182 if (NULL != uri)
183 {
184 GNUNET_FS_uri_destroy (uri);
185 uri = NULL;
186 }
187}
188
189
190/**
191 * Called by FS client to give information about the progress of an
192 * operation.
193 *
194 * @param cls closure
195 * @param info details about the event, specifying the event type
196 * and various bits about the event
197 * @return client-context (for the next progress call
198 * for this operation; should be set to NULL for
199 * SUSPEND and STOPPED events). The value returned
200 * will be passed to future callbacks in the respective
201 * field in the GNUNET_FS_ProgressInfo struct.
202 */
203static void *
204progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
205{
206 const char *s;
207 char *suri;
208
209 switch (info->status)
210 {
211 case GNUNET_FS_STATUS_PUBLISH_START:
212 break;
213
214 case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
215 if (verbose)
216 {
217 s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.eta,
218 GNUNET_YES);
219 fprintf (stdout,
220 _ ("Publishing `%s' at %llu/%llu (%s remaining)\n"),
221 info->value.publish.filename,
222 (unsigned long long) info->value.publish.completed,
223 (unsigned long long) info->value.publish.size,
224 s);
225 }
226 break;
227
228 case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY:
229 if (verbose)
230 {
231 s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.specifics
232 .progress_directory.eta,
233 GNUNET_YES);
234 fprintf (stdout,
235 _ ("Publishing `%s' at %llu/%llu (%s remaining)\n"),
236 info->value.publish.filename,
237 (unsigned long long)
238 info->value.publish.specifics.progress_directory.completed,
239 (unsigned long long)
240 info->value.publish.specifics.progress_directory.total,
241 s);
242 }
243 break;
244
245 case GNUNET_FS_STATUS_PUBLISH_ERROR:
246 fprintf (stderr,
247 _ ("Error publishing: %s.\n"),
248 info->value.publish.specifics.error.message);
249 ret = 1;
250 GNUNET_SCHEDULER_shutdown ();
251 break;
252
253 case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
254 fprintf (stdout,
255 _ ("Publishing `%s' done.\n"),
256 info->value.publish.filename);
257 suri =
258 GNUNET_FS_uri_to_string (info->value.publish.specifics.completed.chk_uri);
259 fprintf (stdout, _ ("URI is `%s'.\n"), suri);
260 GNUNET_free (suri);
261 if (NULL != info->value.publish.specifics.completed.sks_uri)
262 {
263 suri = GNUNET_FS_uri_to_string (
264 info->value.publish.specifics.completed.sks_uri);
265 fprintf (stdout, _ ("Namespace URI is `%s'.\n"), suri);
266 GNUNET_free (suri);
267 }
268 if (NULL == info->value.publish.pctx)
269 {
270 ret = 0;
271 GNUNET_SCHEDULER_shutdown ();
272 }
273 break;
274
275 case GNUNET_FS_STATUS_PUBLISH_STOPPED:
276 GNUNET_break (NULL == pc);
277 return NULL;
278
279 case GNUNET_FS_STATUS_UNINDEX_START:
280 fprintf (stderr, "%s", _ ("Starting cleanup after abort\n"));
281 return NULL;
282
283 case GNUNET_FS_STATUS_UNINDEX_PROGRESS:
284 return NULL;
285
286 case GNUNET_FS_STATUS_UNINDEX_COMPLETED:
287 fprintf (stderr, "%s", _ ("Cleanup after abort completed.\n"));
288 GNUNET_FS_unindex_stop (info->value.unindex.uc);
289 return NULL;
290
291 case GNUNET_FS_STATUS_UNINDEX_ERROR:
292 fprintf (stderr, "%s", _ ("Cleanup after abort failed.\n"));
293 GNUNET_FS_unindex_stop (info->value.unindex.uc);
294 return NULL;
295
296 case GNUNET_FS_STATUS_UNINDEX_STOPPED:
297 return NULL;
298
299 default:
300 fprintf (stderr, _ ("Unexpected status: %d\n"), info->status);
301 return NULL;
302 }
303 return ""; /* non-null */
304}
305
306
307/**
308 * Print metadata entries (except binary
309 * metadata and the filename).
310 *
311 * @param cls closure
312 * @param plugin_name name of the plugin that generated the meta data
313 * @param type type of the meta data
314 * @param format format of data
315 * @param data_mime_type mime type of @a data
316 * @param data value of the meta data
317 * @param data_size number of bytes in @a data
318 * @return always 0
319 */
320static int
321meta_printer (void *cls,
322 const char *plugin_name,
323 enum EXTRACTOR_MetaType type,
324 enum EXTRACTOR_MetaFormat format,
325 const char *data_mime_type,
326 const char *data,
327 size_t data_size)
328{
329 if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
330 (EXTRACTOR_METAFORMAT_C_STRING != format))
331 return 0;
332 if (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type)
333 return 0;
334#if HAVE_LIBEXTRACTOR
335 fprintf (stdout, "\t%s - %s\n", EXTRACTOR_metatype_to_string (type), data);
336#else
337 fprintf (stdout, "\t%d - %s\n", type, data);
338#endif
339 return 0;
340}
341
342
343/**
344 * Iterator printing keywords
345 *
346 * @param cls closure
347 * @param keyword the keyword
348 * @param is_mandatory is the keyword mandatory (in a search)
349 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to abort
350 */
351static int
352keyword_printer (void *cls, const char *keyword, int is_mandatory)
353{
354 fprintf (stdout, "\t%s\n", keyword);
355 return GNUNET_OK;
356}
357
358
359/**
360 * Function called on all entries before the publication. This is
361 * where we perform modifications to the default based on command-line
362 * options.
363 *
364 * @param cls closure
365 * @param fi the entry in the publish-structure
366 * @param length length of the file or directory
367 * @param m metadata for the file or directory (can be modified)
368 * @param uri pointer to the keywords that will be used for this entry (can be modified)
369 * @param bo block options
370 * @param do_index should we index?
371 * @param client_info pointer to client context set upon creation (can be modified)
372 * @return #GNUNET_OK to continue, #GNUNET_NO to remove
373 * this entry from the directory, #GNUNET_SYSERR
374 * to abort the iteration
375 */
376static int
377publish_inspector (void *cls,
378 struct GNUNET_FS_FileInformation *fi,
379 uint64_t length,
380 struct GNUNET_FS_MetaData *m,
381 struct GNUNET_FS_Uri **uri,
382 struct GNUNET_FS_BlockOptions *bo,
383 int *do_index,
384 void **client_info)
385{
386 char *fn;
387 char *fs;
388 struct GNUNET_FS_Uri *new_uri;
389
390 if (cls == fi)
391 return GNUNET_OK;
392 if ((disable_extractor) && (NULL != *uri))
393 {
394 GNUNET_FS_uri_destroy (*uri);
395 *uri = NULL;
396 }
397 if (NULL != topKeywords)
398 {
399 if (NULL != *uri)
400 {
401 new_uri = GNUNET_FS_uri_ksk_merge (topKeywords, *uri);
402 GNUNET_FS_uri_destroy (*uri);
403 *uri = new_uri;
404 GNUNET_FS_uri_destroy (topKeywords);
405 }
406 else
407 {
408 *uri = topKeywords;
409 }
410 topKeywords = NULL;
411 }
412 if (NULL != meta)
413 {
414 GNUNET_FS_meta_data_merge (m, meta);
415 GNUNET_FS_meta_data_destroy (meta);
416 meta = NULL;
417 }
418 if (enable_creation_time)
419 GNUNET_FS_meta_data_add_publication_date (m);
420 if (extract_only)
421 {
422 fn = GNUNET_FS_meta_data_get_by_type (
423 m,
424 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
425 fs = GNUNET_STRINGS_byte_size_fancy (length);
426 fprintf (stdout, _ ("Meta data for file `%s' (%s)\n"), fn, fs);
427 GNUNET_FS_meta_data_iterate (m, &meta_printer, NULL);
428 fprintf (stdout, _ ("Keywords for file `%s' (%s)\n"), fn, fs);
429 GNUNET_free (fn);
430 GNUNET_free (fs);
431 if (NULL != *uri)
432 GNUNET_FS_uri_ksk_get_keywords (*uri, &keyword_printer, NULL);
433 fprintf (stdout, "%s", "\n");
434 }
435 if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (m))
436 GNUNET_FS_file_information_inspect (fi, &publish_inspector, fi);
437 return GNUNET_OK;
438}
439
440
441/**
442 * Function called upon completion of the publishing
443 * of the UBLOCK for the SKS URI. As this is the last
444 * step, stop our interaction with FS (clean up).
445 *
446 * @param cls NULL (closure)
447 * @param sks_uri URI for the block that was published
448 * @param emsg error message, NULL on success
449 */
450static void
451uri_sks_continuation (void *cls,
452 const struct GNUNET_FS_Uri *sks_uri,
453 const char *emsg)
454{
455 if (NULL != emsg)
456 {
457 fprintf (stderr, "%s\n", emsg);
458 ret = 1;
459 }
460 GNUNET_SCHEDULER_shutdown ();
461}
462
463
464/**
465 * Function called upon completion of the publishing
466 * of the UBLOCK for the KSK URI. Continue with
467 * publishing the SKS URI (if applicable) or clean up.
468 *
469 * @param cls NULL (closure)
470 * @param ksk_uri URI for the block that was published
471 * @param emsg error message, NULL on success
472 */
473static void
474uri_ksk_continuation (void *cls,
475 const struct GNUNET_FS_Uri *ksk_uri,
476 const char *emsg)
477{
478 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
479 const struct GNUNET_CRYPTO_PrivateKey *pk;
480
481 if (NULL != emsg)
482 {
483 fprintf (stderr, "%s\n", emsg);
484 ret = 1;
485 }
486 if (NULL == namespace)
487 {
488 GNUNET_SCHEDULER_shutdown ();
489 return;
490 }
491 pk = GNUNET_IDENTITY_ego_get_private_key (namespace);
492 if (GNUNET_PUBLIC_KEY_TYPE_ECDSA != ntohl (pk->type))
493 return;
494 priv = &pk->ecdsa_key;
495 GNUNET_FS_publish_sks (ctx,
496 priv,
497 this_id,
498 next_id,
499 meta,
500 uri,
501 &bo,
502 GNUNET_FS_PUBLISH_OPTION_NONE,
503 &uri_sks_continuation,
504 NULL);
505}
506
507
508/**
509 * Iterate over the results from the directory scan and extract
510 * the desired information for the publishing operation.
511 *
512 * @param item root with the data from the directory scan
513 * @return handle with the information for the publishing operation
514 */
515static struct GNUNET_FS_FileInformation *
516get_file_information (struct GNUNET_FS_ShareTreeItem *item)
517{
518 struct GNUNET_FS_FileInformation *fi;
519 struct GNUNET_FS_FileInformation *fic;
520 struct GNUNET_FS_ShareTreeItem *child;
521
522 if (GNUNET_YES == item->is_directory)
523 {
524 if (NULL == item->meta)
525 item->meta = GNUNET_FS_meta_data_create ();
526 GNUNET_FS_meta_data_delete (item->meta,
527 EXTRACTOR_METATYPE_MIMETYPE,
528 NULL,
529 0);
530 GNUNET_FS_meta_data_make_directory (item->meta);
531 if (NULL == item->ksk_uri)
532 {
533 const char *mime = GNUNET_FS_DIRECTORY_MIME;
534 item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime);
535 }
536 else
537 GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri,
538 GNUNET_FS_DIRECTORY_MIME,
539 GNUNET_NO);
540 fi = GNUNET_FS_file_information_create_empty_directory (ctx,
541 NULL,
542 item->ksk_uri,
543 item->meta,
544 &bo,
545 item->filename);
546 for (child = item->children_head; child; child = child->next)
547 {
548 fic = get_file_information (child);
549 GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
550 }
551 }
552 else
553 {
554 fi = GNUNET_FS_file_information_create_from_file (ctx,
555 NULL,
556 item->filename,
557 item->ksk_uri,
558 item->meta,
559 ! do_insert,
560 &bo);
561 }
562 return fi;
563}
564
565
566/**
567 * We've finished scanning the directory and optimized the meta data.
568 * Begin the publication process.
569 *
570 * @param directory_scan_result result from the directory scan, freed in this function
571 */
572static void
573directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result)
574{
575 struct GNUNET_FS_FileInformation *fi;
576 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
577 const struct GNUNET_CRYPTO_PrivateKey *pk;
578
579 fi = get_file_information (directory_scan_result);
580 GNUNET_FS_share_tree_free (directory_scan_result);
581 if (NULL == fi)
582 {
583 fprintf (stderr, "%s", _ ("Could not publish\n"));
584 ret = 1;
585 GNUNET_SCHEDULER_shutdown ();
586 return;
587 }
588 GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL);
589 if (extract_only)
590 {
591 GNUNET_FS_file_information_destroy (fi, NULL, NULL);
592 GNUNET_SCHEDULER_shutdown ();
593 return;
594 }
595 priv = NULL;
596 if (NULL != namespace)
597 {
598 pk = GNUNET_IDENTITY_ego_get_private_key (namespace);
599 GNUNET_assert (GNUNET_PUBLIC_KEY_TYPE_ECDSA == ntohl (pk->type));
600 priv = &pk->ecdsa_key;
601 }
602 pc = GNUNET_FS_publish_start (ctx,
603 fi,
604 priv,
605 this_id,
606 next_id,
607 (do_simulate)
608 ? GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY
609 : GNUNET_FS_PUBLISH_OPTION_NONE);
610 if (NULL == pc)
611 {
612 fprintf (stderr, "%s", _ ("Could not start publishing.\n"));
613 ret = 1;
614 GNUNET_SCHEDULER_shutdown ();
615 return;
616 }
617}
618
619
620/**
621 * Function called by the directory scanner as we build the tree
622 * that we will need to publish later.
623 *
624 * @param cls closure
625 * @param filename which file we are making progress on
626 * @param is_directory #GNUNET_YES if this is a directory,
627 * #GNUNET_NO if this is a file
628 * #GNUNET_SYSERR if it is neither (or unknown)
629 * @param reason kind of progress we are making
630 */
631static void
632directory_scan_cb (void *cls,
633 const char *filename,
634 int is_directory,
635 enum GNUNET_FS_DirScannerProgressUpdateReason reason)
636{
637 struct GNUNET_FS_ShareTreeItem *directory_scan_result;
638
639 switch (reason)
640 {
641 case GNUNET_FS_DIRSCANNER_FILE_START:
642 if (verbose > 1)
643 {
644 if (is_directory == GNUNET_YES)
645 fprintf (stdout, _ ("Scanning directory `%s'.\n"), filename);
646 else
647 fprintf (stdout, _ ("Scanning file `%s'.\n"), filename);
648 }
649 break;
650
651 case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
652 fprintf (stderr,
653 _ ("There was trouble processing file `%s', skipping it.\n"),
654 filename);
655 break;
656
657 case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
658 if (verbose)
659 fprintf (stdout, "%s", _ ("Preprocessing complete.\n"));
660 break;
661
662 case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
663 if (verbose > 2)
664 fprintf (stdout,
665 _ ("Extracting meta data from file `%s' complete.\n"),
666 filename);
667 break;
668
669 case GNUNET_FS_DIRSCANNER_FINISHED:
670 if (verbose > 1)
671 fprintf (stdout, "%s", _ ("Meta data extraction has finished.\n"));
672 directory_scan_result = GNUNET_FS_directory_scan_get_result (ds);
673 ds = NULL;
674 GNUNET_FS_share_tree_trim (directory_scan_result);
675 directory_trim_complete (directory_scan_result);
676 break;
677
678 case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
679 fprintf (stdout, "%s", _ ("Error scanning directory.\n"));
680 ret = 1;
681 GNUNET_SCHEDULER_shutdown ();
682 break;
683
684 default:
685 GNUNET_assert (0);
686 break;
687 }
688 fflush (stdout);
689}
690
691
692/**
693 * Continuation proceeding with initialization after identity subsystem
694 * has been initialized.
695 *
696 * @param args0 filename to publish
697 */
698static void
699identity_continuation (const char *args0)
700{
701 char *ex;
702 char *emsg;
703
704 if ((NULL != pseudonym) && (NULL == namespace))
705 {
706 fprintf (stderr, _ ("Selected pseudonym `%s' unknown\n"), pseudonym);
707 ret = 1;
708 GNUNET_SCHEDULER_shutdown ();
709 return;
710 }
711 if (NULL != uri_string)
712 {
713 emsg = NULL;
714 if (NULL == (uri = GNUNET_FS_uri_parse (uri_string, &emsg)))
715 {
716 fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg);
717 GNUNET_free (emsg);
718 ret = 1;
719 GNUNET_SCHEDULER_shutdown ();
720 return;
721 }
722 GNUNET_FS_publish_ksk (ctx,
723 topKeywords,
724 meta,
725 uri,
726 &bo,
727 GNUNET_FS_PUBLISH_OPTION_NONE,
728 &uri_ksk_continuation,
729 NULL);
730 return;
731 }
732 if (GNUNET_OK !=
733 GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex))
734 ex = NULL;
735 if (0 != access (args0, R_OK))
736 {
737 fprintf (stderr,
738 _ ("Failed to access `%s': %s\n"),
739 args0,
740 strerror (errno));
741 GNUNET_free (ex);
742 return;
743 }
744 ds = GNUNET_FS_directory_scan_start (args0,
745 disable_extractor,
746 ex,
747 &directory_scan_cb,
748 NULL);
749 if (NULL == ds)
750 {
751 fprintf (
752 stderr,
753 "%s",
754 _ (
755 "Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n"));
756 GNUNET_free (ex);
757 return;
758 }
759 GNUNET_free (ex);
760}
761
762
763/**
764 * Function called by identity service with known pseudonyms.
765 *
766 * @param cls closure with 'const char *' of filename to publish
767 * @param ego ego handle
768 * @param ctx context for application to store data for this ego
769 * (during the lifetime of this process, initially NULL)
770 * @param name name assigned by the user for this ego,
771 * NULL if the user just deleted the ego and it
772 * must thus no longer be used
773 */
774static void
775identity_cb (void *cls,
776 struct GNUNET_IDENTITY_Ego *ego,
777 void **ctx,
778 const char *name)
779{
780 const char *args0 = cls;
781
782 if (NULL == ego)
783 {
784 identity_continuation (args0);
785 return;
786 }
787 if (NULL == name)
788 return;
789 if (0 == strcmp (name, pseudonym))
790 namespace = ego;
791}
792
793
794/**
795 * Main function that will be run by the scheduler.
796 *
797 * @param cls closure
798 * @param args remaining command-line arguments
799 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
800 * @param c configuration
801 */
802static void
803run (void *cls,
804 char *const *args,
805 const char *cfgfile,
806 const struct GNUNET_CONFIGURATION_Handle *c)
807{
808 /* check arguments */
809 if ((NULL != uri_string) && (extract_only))
810 {
811 printf (_ ("Cannot extract metadata from a URI!\n"));
812 ret = -1;
813 return;
814 }
815 if (((NULL == uri_string) || (extract_only)) &&
816 ((NULL == args[0]) || (NULL != args[1])))
817 {
818 printf (_ ("You must specify one and only one filename for insertion.\n"));
819 ret = -1;
820 return;
821 }
822 if ((NULL != uri_string) && (NULL != args[0]))
823 {
824 printf (_ ("You must NOT specify an URI and a filename.\n"));
825 ret = -1;
826 return;
827 }
828 if (NULL != pseudonym)
829 {
830 if (NULL == this_id)
831 {
832 fprintf (stderr,
833 _ ("Option `%s' is required when using option `%s'.\n"),
834 "-t",
835 "-P");
836 ret = -1;
837 return;
838 }
839 }
840 else
841 { /* ordinary insertion checks */
842 if (NULL != next_id)
843 {
844 fprintf (stderr,
845 _ ("Option `%s' makes no sense without option `%s'.\n"),
846 "-N",
847 "-P");
848 ret = -1;
849 return;
850 }
851 if (NULL != this_id)
852 {
853 fprintf (stderr,
854 _ ("Option `%s' makes no sense without option `%s'.\n"),
855 "-t",
856 "-P");
857 ret = -1;
858 return;
859 }
860 }
861 cfg = c;
862 ctx = GNUNET_FS_start (cfg,
863 "gnunet-publish",
864 &progress_cb,
865 NULL,
866 GNUNET_FS_FLAGS_NONE,
867 GNUNET_FS_OPTIONS_END);
868 if (NULL == ctx)
869 {
870 fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
871 ret = 1;
872 return;
873 }
874 GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL);
875 if (NULL != pseudonym)
876 identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, args[0]);
877 else
878 identity_continuation (args[0]);
879}
880
881
882/**
883 * The main function to publish content to GNUnet.
884 *
885 * @param argc number of arguments from the command line
886 * @param argv command line arguments
887 * @return 0 ok, 1 on error
888 */
889int
890main (int argc, char *const *argv)
891{
892 struct GNUNET_GETOPT_CommandLineOption options[] =
893 { GNUNET_GETOPT_option_uint ('a',
894 "anonymity",
895 "LEVEL",
896 gettext_noop (
897 "set the desired LEVEL of sender-anonymity"),
898 &bo.anonymity_level),
899 GNUNET_GETOPT_option_flag (
900 'D',
901 "disable-extractor",
902 gettext_noop ("do not use libextractor to add keywords or metadata"),
903 &disable_extractor),
904 GNUNET_GETOPT_option_flag ('E',
905 "enable-creation-time",
906 gettext_noop (
907 "enable adding the creation time to the "
908 "metadata of the uploaded file"),
909 &enable_creation_time),
910 GNUNET_GETOPT_option_flag ('e',
911 "extract",
912 gettext_noop (
913 "print list of extracted keywords that would "
914 "be used, but do not perform upload"),
915 &extract_only),
916 GNUNET_FS_GETOPT_KEYWORDS (
917 'k',
918 "key",
919 "KEYWORD",
920 gettext_noop (
921 "add an additional keyword for the top-level "
922 "file or directory (this option can be specified multiple times)"),
923 &topKeywords),
924 GNUNET_FS_GETOPT_METADATA (
925 'm',
926 "meta",
927 "TYPE:VALUE",
928 gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
929 &meta),
930 GNUNET_GETOPT_option_flag (
931 'n',
932 "noindex",
933 gettext_noop ("do not index, perform full insertion (stores "
934 "entire file in encrypted form in GNUnet database)"),
935 &do_insert),
936 GNUNET_GETOPT_option_string (
937 'N',
938 "next",
939 "ID",
940 gettext_noop ("specify ID of an updated version to be "
941 "published in the future (for namespace insertions only)"),
942 &next_id),
943 GNUNET_GETOPT_option_uint ('p',
944 "priority",
945 "PRIORITY",
946 gettext_noop (
947 "specify the priority of the content"),
948 &bo.content_priority),
949 GNUNET_GETOPT_option_string ('P',
950 "pseudonym",
951 "NAME",
952 gettext_noop (
953 "publish the files under the pseudonym "
954 "NAME (place file into namespace)"),
955 &pseudonym),
956 GNUNET_GETOPT_option_uint ('r',
957 "replication",
958 "LEVEL",
959 gettext_noop (
960 "set the desired replication LEVEL"),
961 &bo.replication_level),
962 GNUNET_GETOPT_option_flag ('s',
963 "simulate-only",
964 gettext_noop (
965 "only simulate the process but do not do "
966 "any actual publishing (useful to compute URIs)"),
967 &do_simulate),
968 GNUNET_GETOPT_option_string ('t',
969 "this",
970 "ID",
971 gettext_noop (
972 "set the ID of this version of the publication "
973 "(for namespace insertions only)"),
974 &this_id),
975 GNUNET_GETOPT_option_string (
976 'u',
977 "uri",
978 "URI",
979 gettext_noop (
980 "URI to be published (can be used instead of passing a "
981 "file to add keywords to the file with the respective URI)"),
982 &uri_string),
983
984 GNUNET_GETOPT_option_verbose (&verbose),
985
986 GNUNET_GETOPT_OPTION_END };
987
988 bo.expiration_time =
989 GNUNET_TIME_year_to_time (GNUNET_TIME_get_current_year () + 2);
990
991 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
992 return 2;
993 ret =
994 (GNUNET_OK ==
995 GNUNET_PROGRAM_run (argc,
996 argv,
997 "gnunet-publish [OPTIONS] FILENAME",
998 gettext_noop ("Publish a file or directory on GNUnet"),
999 options,
1000 &run,
1001 NULL))
1002 ? ret
1003 : 1;
1004 GNUNET_free_nz ((void *) argv);
1005 return ret;
1006}
1007
1008
1009/* end of gnunet-publish.c */
diff --git a/src/cli/fs/gnunet-search.c b/src/cli/fs/gnunet-search.c
new file mode 100644
index 000000000..a72cf97cc
--- /dev/null
+++ b/src/cli/fs/gnunet-search.c
@@ -0,0 +1,801 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 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 fs/gnunet-search.c
22 * @brief searching for files on GNUnet
23 * @author Christian Grothoff
24 * @author Krista Bennett
25 * @author James Blackwell
26 * @author Igor Wronsky
27 * @author madmurphy
28 */
29#include "platform.h"
30#include <ctype.h>
31#include <inttypes.h>
32#include <limits.h>
33
34#include "gnunet_fs_service.h"
35
36
37#define GNUNET_SEARCH_log(kind, ...) \
38 GNUNET_log_from (kind, "gnunet-search", __VA_ARGS__)
39
40
41/* The default settings that we use for the printed output */
42
43#define DEFAULT_DIR_FORMAT "#%n:\ngnunet-download -o \"%f\" -R %u\n\n"
44#define HELP_DEFAULT_DIR_FORMAT "#%n:\\ngnunet-download -o \"%f\" -R %u\\n\\n"
45#define DEFAULT_FILE_FORMAT "#%n:\ngnunet-download -o \"%f\" %u\n\n"
46#define HELP_DEFAULT_FILE_FORMAT "#%n:\\ngnunet-download -o \"%f\" %u\\n\\n"
47#define VERB_DEFAULT_DIR_FORMAT DEFAULT_DIR_FORMAT "%a\n"
48#define VERB_DEFAULT_FILE_FORMAT DEFAULT_FILE_FORMAT "%a\n"
49
50#if HAVE_LIBEXTRACTOR
51#define DEFAULT_META_FORMAT " %t: %p\n"
52#define HELP_DEFAULT_META_FORMAT " %t: %p\\n"
53#define HELP_EXTRACTOR_TEXTADD ", %t"
54#else
55#define DEFAULT_META_FORMAT " MetaType #%i: %p\n"
56#define HELP_DEFAULT_META_FORMAT " MetaType #%i: %p\\n"
57#define HELP_EXTRACTOR_TEXTADD ""
58#endif
59
60#define GENERIC_DIRECTORY_NAME "collection"
61#define GENERIC_FILE_NAME "no-name"
62#define GENERIC_FILE_MIMETYPE "application/octet-stream"
63
64
65enum GNUNET_SEARCH_MetadataPrinterFlags
66{
67 METADATA_PRINTER_FLAG_NONE = 0,
68 METADATA_PRINTER_FLAG_ONE_RUN = 1,
69 METADATA_PRINTER_FLAG_HAVE_TYPE = 2
70};
71
72
73struct GNUNET_SEARCH_MetadataPrinterInfo
74{
75 unsigned int counter;
76 unsigned int flags;
77 int type;
78};
79
80
81static int ret;
82
83static const struct GNUNET_CONFIGURATION_Handle *cfg;
84
85static struct GNUNET_FS_Handle *ctx;
86
87static struct GNUNET_FS_SearchContext *sc;
88
89static char *output_filename;
90
91static char *format_string;
92
93static char *dir_format_string;
94
95static char *meta_format_string;
96
97static struct GNUNET_FS_DirectoryBuilder *db;
98
99static unsigned int anonymity = 1;
100
101/**
102 * Timeout for the search, 0 means to wait for CTRL-C.
103 */
104static struct GNUNET_TIME_Relative timeout;
105
106static unsigned int results_limit;
107
108static unsigned int results;
109
110static unsigned int verbose;
111
112static int bookmark_only;
113
114static int local_only;
115
116static int silent_mode;
117
118static struct GNUNET_SCHEDULER_Task *tt;
119
120static int stop_searching;
121
122
123/**
124 * Print the escape sequence at the beginning of a string.
125 *
126 * @param esc a string that **must** begin with a backslash (the function only
127 * assumes that it does, but does not check)
128 * @return the fragment that follows what has been printed
129 * @author madmurphy
130 *
131 * If `"\\nfoo"` is passed as argument, this function prints a new line and
132 * returns `"foo"`
133 */
134static const char *
135print_escape_sequence (const char *const esc)
136{
137 unsigned int probe;
138 const char *cursor = esc + 1;
139 char tmp;
140 switch (*cursor)
141 {
142 /* Trivia */
143 case '\\': putchar ('\\'); return cursor + 1;
144 case 'a': putchar ('\a'); return cursor + 1;
145 case 'b': putchar ('\b'); return cursor + 1;
146 case 'e': putchar ('\x1B'); return cursor + 1;
147 case 'f': putchar ('\f'); return cursor + 1;
148 case 'n': putchar ('\n'); return cursor + 1;
149 case 'r': putchar ('\r'); return cursor + 1;
150 case 't': putchar ('\t'); return cursor + 1;
151 case 'v': putchar ('\v'); return cursor + 1;
152
153 /* Possibly hexadecimal code point */
154 case 'x':
155 probe = 0;
156 while (probe < 256 && isxdigit ((tmp = *++cursor)))
157 probe = (probe << 4) + tmp - (tmp > 96 ? 87 : tmp > 64 ? 55 : 48);
158 goto maybe_codepoint;
159
160 /* Possibly octal code point */
161 case '0': case '1': case '2': case '3':
162 case '4': case '5': case '6': case '7':
163 probe = *cursor++ - 48;
164 do probe = (probe << 3) + *cursor++ - 48;
165 while (probe < 256 && cursor < esc + 4 && *cursor > 47 && *cursor < 56);
166 goto maybe_codepoint;
167
168 /* Boredom */
169 case '\0': putchar ('\\'); return cursor;
170 default: printf ("\\%c", *cursor); return cursor + 1;
171 }
172
173 maybe_codepoint:
174 if (probe < 256)
175 putchar (probe);
176 else
177 fwrite (esc, 1, cursor - esc, stdout);
178 return cursor;
179}
180
181
182/**
183 * Type of a function that libextractor calls for each
184 * meta data item found.
185 *
186 * @param cls closure (user-defined, used for the iteration info)
187 * @param plugin_name name of the plugin that produced this value;
188 * special values can be used (e.g. '&lt;zlib&gt;' for zlib being
189 * used in the main libextractor library and yielding
190 * meta data).
191 * @param type libextractor-type describing the meta data
192 * @param format basic format information about data
193 * @param data_mime_type mime-type of data (not of the original file);
194 * can be NULL (if mime-type is not known)
195 * @param data actual meta-data found
196 * @param data_size number of bytes in @a data
197 * @return 0 to continue extracting, 1 to abort
198 */
199static int
200item_printer (void *const cls,
201 const char *const plugin_name,
202 const enum EXTRACTOR_MetaType type,
203 const enum EXTRACTOR_MetaFormat format,
204 const char *const data_mime_type,
205 const char *const data,
206 const size_t data_size)
207{
208#define info ((struct GNUNET_SEARCH_MetadataPrinterInfo *) cls)
209 if ((format != EXTRACTOR_METAFORMAT_UTF8 &&
210 format != EXTRACTOR_METAFORMAT_C_STRING) ||
211 type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME)
212 return 0;
213 info->counter++;
214 if ((info->flags & METADATA_PRINTER_FLAG_HAVE_TYPE) && type != info->type)
215 return 0;
216
217 const char *cursor = meta_format_string;
218 const char *next_spec = strchr (cursor, '%');
219 const char *next_esc = strchr (cursor, '\\');
220
221 parse_format:
222
223 /* If an escape sequence exists before the next format specifier... */
224 if (next_esc && (! next_spec || next_esc < next_spec))
225 {
226 if (next_esc > cursor)
227 fwrite (cursor, 1, next_esc - cursor, stdout);
228
229 cursor = print_escape_sequence (next_esc);
230 next_esc = strchr (cursor, '\\');
231 goto parse_format;
232 }
233
234 /* If a format specifier exists before the next escape sequence... */
235 if (next_spec && (! next_esc || next_spec < next_esc))
236 {
237 if (next_spec > cursor)
238 fwrite (cursor, 1, next_spec - cursor, stdout);
239
240 switch (*++next_spec)
241 {
242 case '%': putchar ('%'); break;
243 case 'i': printf ("%d", type); break;
244 case 'l': printf ("%lu", (long unsigned int) data_size); break;
245 case 'n': printf ("%u", info->counter); break;
246 case 'p': printf ("%s", data); break;
247#if HAVE_LIBEXTRACTOR
248 case 't':
249 printf ("%s",
250 dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN,
251 EXTRACTOR_metatype_to_string (type)));
252 break;
253#endif
254 case 'w': printf ("%s", plugin_name); break;
255 case '\0': putchar ('%'); return 0;
256 default: printf ("%%%c", *next_spec); break;
257 }
258 cursor = next_spec + 1;
259 next_spec = strchr (cursor, '%');
260 goto parse_format;
261 }
262
263 if (*cursor)
264 printf ("%s", cursor);
265
266 return info->flags & METADATA_PRINTER_FLAG_ONE_RUN;
267#undef info
268}
269
270
271/**
272 * Print a search result according to the current formats
273 *
274 * @param filename the filename for this result
275 * @param uri the `struct GNUNET_FS_Uri` this result refers to
276 * @param metadata the `struct GNUNET_FS_MetaData` associated with this
277 result
278 * @param resultnum the result number
279 * @param is_directory GNUNET_YES if this is a directory, otherwise GNUNET_NO
280 * @author madmurphy
281 */
282static void
283print_search_result (const char *const filename,
284 const struct GNUNET_FS_Uri *const uri,
285 const struct GNUNET_FS_MetaData *const metadata,
286 const unsigned int resultnum,
287 const int is_directory)
288{
289
290 const char *cursor = GNUNET_YES == is_directory ?
291 dir_format_string
292 : format_string;
293
294 const char *next_spec = strchr (cursor, '%');
295 const char *next_esc = strchr (cursor, '\\');
296 char *placeholder;
297 struct GNUNET_SEARCH_MetadataPrinterInfo info;
298
299 parse_format:
300 /* If an escape sequence exists before the next format specifier... */
301 if (next_esc && (! next_spec || next_esc < next_spec))
302 {
303 if (next_esc > cursor)
304 fwrite (cursor, 1, next_esc - cursor, stdout);
305
306 cursor = print_escape_sequence (next_esc);
307 next_esc = strchr (cursor, '\\');
308 goto parse_format;
309 }
310
311 /* If a format specifier exists before the next escape sequence... */
312 if (next_spec && (! next_esc || next_spec < next_esc))
313 {
314 if (next_spec > cursor)
315 fwrite (cursor, 1, next_spec - cursor, stdout);
316
317 switch (*++next_spec)
318 {
319 /* All metadata fields */
320 case 'a':
321 info.flags = METADATA_PRINTER_FLAG_NONE;
322
323 iterate_meta:
324 info.counter = 0;
325 GNUNET_FS_meta_data_iterate (metadata, &item_printer, &info);
326 break;
327 /* File's name */
328 case 'f':
329 if (GNUNET_YES == is_directory)
330 {
331 printf ("%s%s", filename, GNUNET_FS_DIRECTORY_EXT);
332 break;
333 }
334 printf ("%s", filename);
335 break;
336 /* Only the first metadata field */
337 case 'j':
338 info.flags = METADATA_PRINTER_FLAG_ONE_RUN;
339 goto iterate_meta;
340 /* File name's length */
341 case 'l':
342 printf ("%lu",
343 (long unsigned int) (GNUNET_YES == is_directory ?
344 strlen (filename)
345 + (sizeof(GNUNET_FS_DIRECTORY_EXT) - 1)
346 :
347 strlen (filename)));
348 break;
349 /* File's mime type */
350 case 'm':
351 if (GNUNET_YES == is_directory)
352 {
353 printf ("%s", GNUNET_FS_DIRECTORY_MIME);
354 break;
355 }
356 placeholder = GNUNET_FS_meta_data_get_by_type (
357 metadata,
358 EXTRACTOR_METATYPE_MIMETYPE);
359 printf ("%s", placeholder ? placeholder : GENERIC_FILE_MIMETYPE);
360 GNUNET_free (placeholder);
361 break;
362 /* Result number */
363 case 'n': printf ("%u", resultnum); break;
364 /* File's size */
365 case 's':
366 printf ("%" PRIu64, GNUNET_FS_uri_chk_get_file_size (uri));
367 break;
368 /* File's URI */
369 case 'u':
370 placeholder = GNUNET_FS_uri_to_string (uri);
371 printf ("%s", placeholder);
372 GNUNET_free (placeholder);
373 break;
374
375 /* We can add as many cases as we want here... */
376
377 /* Handle `%123#a` and `%123#j` (e.g. `%5#j` is a book title) */
378 case '0': case '1': case '2': case '3': case '4':
379 case '5': case '6': case '7': case '8': case '9':
380 cursor = next_spec;
381 info.type = *cursor - 48;
382 while (isdigit (*++cursor) && info.type < (INT_MAX - *cursor + 48) / 10)
383 info.type = info.type * 10 + *cursor - 48;
384 if (info.type == 0 || *cursor != '#')
385 goto not_a_specifier;
386 switch (*++cursor)
387 {
388 /* All metadata fields of type `info.type` */
389 case 'a':
390 next_spec = cursor;
391 info.flags = METADATA_PRINTER_FLAG_HAVE_TYPE;
392 goto iterate_meta;
393
394 /* Only the first metadata field of type `info.type` */
395 case 'j':
396 next_spec = cursor;
397 info.flags = METADATA_PRINTER_FLAG_HAVE_TYPE
398 | METADATA_PRINTER_FLAG_ONE_RUN;
399 goto iterate_meta;
400 }
401 goto not_a_specifier;
402
403 /* All other cases */
404 case '%': putchar ('%'); break;
405 case '\0': putchar ('%'); return;
406
407 not_a_specifier:
408 default: printf ("%%%c", *next_spec); break;
409 }
410 cursor = next_spec + 1;
411 next_spec = strchr (cursor, '%');
412 goto parse_format;
413 }
414
415 if (*cursor)
416 printf ("%s", cursor);
417}
418
419
420static void
421clean_task (void *const cls)
422{
423 size_t dsize;
424 void *ddata;
425
426 GNUNET_FS_stop (ctx);
427 ctx = NULL;
428 if (output_filename == NULL)
429 return;
430 if (GNUNET_OK !=
431 GNUNET_FS_directory_builder_finish (db, &dsize, &ddata))
432 {
433 GNUNET_break (0);
434 GNUNET_free (output_filename);
435 return;
436 }
437 (void) GNUNET_DISK_directory_remove (output_filename);
438 if (GNUNET_OK !=
439 GNUNET_DISK_fn_write (output_filename,
440 ddata,
441 dsize,
442 GNUNET_DISK_PERM_USER_READ
443 | GNUNET_DISK_PERM_USER_WRITE))
444 {
445 GNUNET_SEARCH_log (GNUNET_ERROR_TYPE_ERROR,
446 _ ("Failed to write directory with search results to "
447 "`%s'\n"),
448 output_filename);
449 }
450 GNUNET_free (ddata);
451 GNUNET_free (output_filename);
452}
453
454
455/**
456 * Called by FS client to give information about the progress of an
457 * operation.
458 *
459 * @param cls closure
460 * @param info details about the event, specifying the event type
461 * and various bits about the event
462 * @return client-context (for the next progress call
463 * for this operation; should be set to NULL for
464 * SUSPEND and STOPPED events). The value returned
465 * will be passed to future callbacks in the respective
466 * field in the GNUNET_FS_ProgressInfo struct.
467 */
468static void *
469progress_cb (void *const cls,
470 const struct GNUNET_FS_ProgressInfo *const info)
471{
472 static unsigned int cnt;
473 int is_directory;
474 char *filename;
475
476 switch (info->status)
477 {
478 case GNUNET_FS_STATUS_SEARCH_START:
479 break;
480
481 case GNUNET_FS_STATUS_SEARCH_RESULT:
482 if (stop_searching)
483 break;
484
485 if (db != NULL)
486 GNUNET_FS_directory_builder_add (
487 db,
488 info->value.search.specifics.result.uri,
489 info->value.search.specifics.result.meta,
490 NULL);
491
492 if (silent_mode)
493 break;
494
495 cnt++;
496 filename = GNUNET_FS_meta_data_get_by_type (
497 info->value.search.specifics.result.meta,
498 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
499 is_directory = GNUNET_FS_meta_data_test_for_directory (
500 info->value.search.specifics.result.meta);
501 if (NULL != filename)
502 {
503 while ((filename[0] != '\0') && ('/' == filename[strlen (filename) - 1]))
504 filename[strlen (filename) - 1] = '\0';
505 GNUNET_DISK_filename_canonicalize (filename);
506 }
507 print_search_result (filename ?
508 filename
509 : is_directory ?
510 GENERIC_DIRECTORY_NAME
511 :
512 GENERIC_FILE_NAME,
513 info->value.search.specifics.result.uri,
514 info->value.search.specifics.result.meta,
515 cnt,
516 is_directory);
517 fflush (stdout);
518 GNUNET_free (filename);
519 results++;
520 if ((results_limit > 0) && (results >= results_limit))
521 {
522 GNUNET_SCHEDULER_shutdown ();
523 /* otherwise the function might keep printing results for a while... */
524 stop_searching = GNUNET_YES;
525 }
526 break;
527
528 case GNUNET_FS_STATUS_SEARCH_UPDATE:
529 case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
530 /* ignore */
531 break;
532
533 case GNUNET_FS_STATUS_SEARCH_ERROR:
534 GNUNET_SEARCH_log (GNUNET_ERROR_TYPE_ERROR,
535 _ ("Error searching: %s.\n"),
536 info->value.search.specifics.error.message);
537 GNUNET_SCHEDULER_shutdown ();
538 break;
539
540 case GNUNET_FS_STATUS_SEARCH_STOPPED:
541 GNUNET_SCHEDULER_add_now (&clean_task, NULL);
542 break;
543
544 default:
545 GNUNET_SEARCH_log (GNUNET_ERROR_TYPE_ERROR,
546 _ ("Unexpected status: %d\n"),
547 info->status);
548 break;
549 }
550 return NULL;
551}
552
553
554static void
555shutdown_task (void *const cls)
556{
557 if (sc != NULL)
558 {
559 GNUNET_FS_search_stop (sc);
560 sc = NULL;
561 }
562}
563
564
565static void
566timeout_task (void *const cls)
567{
568 tt = NULL;
569 stop_searching = GNUNET_YES;
570 GNUNET_SCHEDULER_shutdown ();
571}
572
573
574/**
575 * Main function that will be run by the scheduler.
576 *
577 * @param cls closure
578 * @param args remaining command-line arguments
579 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
580 * @param cfgarg configuration
581 */
582static void
583run (void *const cls,
584 char *const *const args,
585 const char *const cfgfile,
586 const struct GNUNET_CONFIGURATION_Handle *const cfgarg)
587{
588 struct GNUNET_FS_Uri *uri;
589 unsigned int argc;
590 enum GNUNET_FS_SearchOptions options;
591
592 if (silent_mode && bookmark_only)
593 {
594 fprintf (stderr,
595 _ ("Conflicting options --bookmark-only and --silent.\n"));
596 ret = 1;
597 return;
598 }
599 if (bookmark_only && output_filename)
600 {
601 fprintf (stderr,
602 _ ("Conflicting options --bookmark-only and --output.\n"));
603 ret = 1;
604 return;
605 }
606 if (silent_mode && ! output_filename)
607 {
608 fprintf (stderr, _ ("An output file is mandatory for silent mode.\n"));
609 ret = 1;
610 return;
611 }
612 if (NULL == dir_format_string)
613 dir_format_string = format_string ? format_string
614 : verbose ? VERB_DEFAULT_DIR_FORMAT
615 : DEFAULT_DIR_FORMAT;
616 if (NULL == format_string)
617 format_string = verbose ? VERB_DEFAULT_FILE_FORMAT
618 : DEFAULT_FILE_FORMAT;
619 if (NULL == meta_format_string)
620 meta_format_string = DEFAULT_META_FORMAT;
621 argc = 0;
622 while (NULL != args[argc])
623 argc++;
624 uri = GNUNET_FS_uri_ksk_create_from_args (argc, (const char **) args);
625 if (NULL == uri)
626 {
627 fprintf (stderr,
628 "%s",
629 _ ("Could not create keyword URI from arguments.\n"));
630 ret = 1;
631 return;
632 }
633 if (! GNUNET_FS_uri_test_ksk (uri) && ! GNUNET_FS_uri_test_sks (uri))
634 {
635 fprintf (stderr,
636 "%s",
637 _ ("Invalid URI. Valid URIs for searching are keyword query "
638 "URIs\n(\"gnunet://fs/ksk/...\") and namespace content URIs "
639 "(\"gnunet://fs/sks/...\").\n"));
640 GNUNET_FS_uri_destroy (uri);
641 ret = 1;
642 return;
643 }
644 if (bookmark_only)
645 {
646 char *bmstr = GNUNET_FS_uri_to_string (uri);
647 printf ("%s\n", bmstr);
648 GNUNET_free (bmstr);
649 GNUNET_FS_uri_destroy (uri);
650 ret = 0;
651 return;
652 }
653 cfg = cfgarg;
654 ctx = GNUNET_FS_start (cfg,
655 "gnunet-search",
656 &progress_cb,
657 NULL,
658 GNUNET_FS_FLAGS_NONE,
659 GNUNET_FS_OPTIONS_END);
660 if (NULL == ctx)
661 {
662 fprintf (stderr, _ ("Could not initialize the `%s` subsystem.\n"), "FS");
663 GNUNET_FS_uri_destroy (uri);
664 ret = 1;
665 return;
666 }
667 if (output_filename != NULL)
668 db = GNUNET_FS_directory_builder_create (NULL);
669 options = GNUNET_FS_SEARCH_OPTION_NONE;
670 if (local_only)
671 options |= GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY;
672 sc = GNUNET_FS_search_start (ctx, uri, anonymity, options, NULL);
673 GNUNET_FS_uri_destroy (uri);
674 if (NULL == sc)
675 {
676 fprintf (stderr, "%s", _ ("Could not start searching.\n"));
677 GNUNET_FS_stop (ctx);
678 ret = 1;
679 return;
680 }
681 if (0 != timeout.rel_value_us)
682 tt = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, NULL);
683 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
684}
685
686
687/**
688 * The main function to search GNUnet.
689 *
690 * @param argc number of arguments from the command line
691 * @param argv command line arguments
692 * @return 0 ok, an error number on error
693 */
694int
695main (int argc, char *const *argv)
696{
697 struct GNUNET_GETOPT_CommandLineOption options[] =
698 { GNUNET_GETOPT_option_uint (
699 'a',
700 "anonymity",
701 "LEVEL",
702 gettext_noop ("set the desired LEVEL of receiver-anonymity (default: "
703 "1)"),
704 &anonymity),
705 GNUNET_GETOPT_option_flag (
706 'b',
707 "bookmark-only",
708 gettext_noop ("do not search, print only the URI that points to this "
709 "search"),
710 &bookmark_only),
711 GNUNET_GETOPT_option_string (
712 'F',
713 "dir-printf",
714 "FORMAT",
715 gettext_noop ("write search results for directories according to "
716 "FORMAT; accepted placeholders are: %a, %f, %j, %l, %m, "
717 "%n, %s; defaults to the value of --printf when omitted "
718 "or to `" HELP_DEFAULT_DIR_FORMAT "` if --printf is "
719 "omitted too"),
720 &dir_format_string),
721 GNUNET_GETOPT_option_string (
722 'f',
723 "printf",
724 "FORMAT",
725 gettext_noop ("write search results according to FORMAT; accepted "
726 "placeholders are: %a, %f, %j, %l, %m, %n, %s; defaults "
727 "to `" HELP_DEFAULT_FILE_FORMAT "` when omitted"),
728 &format_string),
729 GNUNET_GETOPT_option_string (
730 'i',
731 "iter-printf",
732 "FORMAT",
733 gettext_noop ("when the %a or %j placeholders appear in --printf or "
734 "--dir-printf, list each metadata property according to "
735 "FORMAT; accepted placeholders are: %i, %l, %n, %p"
736 HELP_EXTRACTOR_TEXTADD ", %w; defaults to `"
737 HELP_DEFAULT_META_FORMAT "` when omitted"),
738 &meta_format_string),
739 GNUNET_GETOPT_option_uint ('N',
740 "results",
741 "VALUE",
742 gettext_noop ("automatically terminate search "
743 "after VALUE results are found"),
744 &results_limit),
745 GNUNET_GETOPT_option_flag (
746 'n',
747 "no-network",
748 gettext_noop ("only search the local peer (no P2P network search)"),
749 &local_only),
750 GNUNET_GETOPT_option_string (
751 'o',
752 "output",
753 "FILENAME",
754 gettext_noop ("create a GNUnet directory with search results at "
755 "FILENAME (e.g. `gnunet-search --output=commons"
756 GNUNET_FS_DIRECTORY_EXT " commons`)"),
757 &output_filename),
758 GNUNET_GETOPT_option_flag (
759 's',
760 "silent",
761 gettext_noop ("silent mode (requires the --output argument)"),
762 &silent_mode),
763 GNUNET_GETOPT_option_relative_time (
764 't',
765 "timeout",
766 "DELAY",
767 gettext_noop ("automatically terminate search after DELAY; the value "
768 "given must be a number followed by a space and a time "
769 "unit, for example \"500 ms\"; without a unit it defaults "
770 "to microseconds - 1000000 = 1 second; if 0 or omitted "
771 "it means to wait for CTRL-C"),
772 &timeout),
773 GNUNET_GETOPT_option_increment_uint (
774 'V',
775 "verbose",
776 gettext_noop ("be verbose (append \"%a\\n\" to the default --printf and "
777 "--dir-printf arguments - ignored when these are provided "
778 "by the user)"),
779 &verbose),
780 GNUNET_GETOPT_OPTION_END };
781
782 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
783 return 12;
784
785 if (GNUNET_SYSERR ==
786 GNUNET_PROGRAM_run (argc,
787 argv,
788 "gnunet-search [OPTIONS] KEYWORD1 KEYWORD2 ...",
789 gettext_noop ("Search for files that have been "
790 "published on GNUnet\n"),
791 options,
792 &run,
793 NULL))
794 ret = 1;
795
796 GNUNET_free_nz ((void *) argv);
797 return ret;
798}
799
800
801/* end of gnunet-search.c */
diff --git a/src/cli/fs/gnunet-unindex.c b/src/cli/fs/gnunet-unindex.c
new file mode 100644
index 000000000..326f75a63
--- /dev/null
+++ b/src/cli/fs/gnunet-unindex.c
@@ -0,0 +1,206 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 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 fs/gnunet-unindex.c
22 * @brief unindex files published on GNUnet
23 * @author Christian Grothoff
24 * @author Krista Bennett
25 * @author James Blackwell
26 * @author Igor Wronsky
27 */
28#include "platform.h"
29
30#include "gnunet_fs_service.h"
31
32static int ret;
33
34static unsigned int verbose;
35
36static const struct GNUNET_CONFIGURATION_Handle *cfg;
37
38static struct GNUNET_FS_Handle *ctx;
39
40static struct GNUNET_FS_UnindexContext *uc;
41
42
43static void
44cleanup_task (void *cls)
45{
46 GNUNET_FS_stop (ctx);
47 ctx = NULL;
48}
49
50
51static void
52shutdown_task (void *cls)
53{
54 struct GNUNET_FS_UnindexContext *u;
55
56 if (uc != NULL)
57 {
58 u = uc;
59 uc = NULL;
60 GNUNET_FS_unindex_stop (u);
61 }
62}
63
64
65/**
66 * Called by FS client to give information about the progress of an
67 * operation.
68 *
69 * @param cls closure
70 * @param info details about the event, specifying the event type
71 * and various bits about the event
72 * @return client-context (for the next progress call
73 * for this operation; should be set to NULL for
74 * SUSPEND and STOPPED events). The value returned
75 * will be passed to future callbacks in the respective
76 * field in the GNUNET_FS_ProgressInfo struct.
77 */
78static void *
79progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
80{
81 const char *s;
82
83 switch (info->status)
84 {
85 case GNUNET_FS_STATUS_UNINDEX_START:
86 break;
87
88 case GNUNET_FS_STATUS_UNINDEX_PROGRESS:
89 if (verbose)
90 {
91 s = GNUNET_STRINGS_relative_time_to_string (info->value.unindex.eta,
92 GNUNET_YES);
93 fprintf (stdout,
94 _ ("Unindexing at %llu/%llu (%s remaining)\n"),
95 (unsigned long long) info->value.unindex.completed,
96 (unsigned long long) info->value.unindex.size,
97 s);
98 }
99 break;
100
101 case GNUNET_FS_STATUS_UNINDEX_ERROR:
102 fprintf (stderr,
103 _ ("Error unindexing: %s.\n"),
104 info->value.unindex.specifics.error.message);
105 GNUNET_SCHEDULER_shutdown ();
106 break;
107
108 case GNUNET_FS_STATUS_UNINDEX_COMPLETED:
109 fprintf (stdout, "%s", _ ("Unindexing done.\n"));
110 GNUNET_SCHEDULER_shutdown ();
111 break;
112
113 case GNUNET_FS_STATUS_UNINDEX_STOPPED:
114 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
115 break;
116
117 default:
118 fprintf (stderr, _ ("Unexpected status: %d\n"), info->status);
119 break;
120 }
121 return NULL;
122}
123
124
125/**
126 * Main function that will be run by the scheduler.
127 *
128 * @param cls closure
129 * @param args remaining command-line arguments
130 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
131 * @param c configuration
132 */
133static void
134run (void *cls,
135 char *const *args,
136 const char *cfgfile,
137 const struct GNUNET_CONFIGURATION_Handle *c)
138{
139 /* check arguments */
140 if ((args[0] == NULL) || (args[1] != NULL))
141 {
142 printf (_ ("You must specify one and only one filename for unindexing.\n"));
143 ret = -1;
144 return;
145 }
146 cfg = c;
147 ctx = GNUNET_FS_start (cfg,
148 "gnunet-unindex",
149 &progress_cb,
150 NULL,
151 GNUNET_FS_FLAGS_NONE,
152 GNUNET_FS_OPTIONS_END);
153 if (NULL == ctx)
154 {
155 fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
156 ret = 1;
157 return;
158 }
159 uc = GNUNET_FS_unindex_start (ctx, args[0], NULL);
160 if (NULL == uc)
161 {
162 fprintf (stderr, "%s", _ ("Could not start unindex operation.\n"));
163 GNUNET_FS_stop (ctx);
164 return;
165 }
166 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
167}
168
169
170/**
171 * The main function to unindex content.
172 *
173 * @param argc number of arguments from the command line
174 * @param argv command line arguments
175 * @return 0 ok, 1 on error
176 */
177int
178main (int argc, char *const *argv)
179{
180 struct GNUNET_GETOPT_CommandLineOption options[] = {
181 GNUNET_GETOPT_option_verbose (&verbose),
182
183 GNUNET_GETOPT_OPTION_END
184 };
185
186 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
187 return 2;
188
189 ret = (GNUNET_OK ==
190 GNUNET_PROGRAM_run (
191 argc,
192 argv,
193 "gnunet-unindex [OPTIONS] FILENAME",
194 gettext_noop (
195 "Unindex a file that was previously indexed with gnunet-publish."),
196 options,
197 &run,
198 NULL))
199 ? ret
200 : 1;
201 GNUNET_free_nz ((void *) argv);
202 return ret;
203}
204
205
206/* end of gnunet-unindex.c */
diff --git a/src/cli/fs/meson.build b/src/cli/fs/meson.build
new file mode 100644
index 000000000..1b29dd56d
--- /dev/null
+++ b/src/cli/fs/meson.build
@@ -0,0 +1,51 @@
1executable ('gnunet-search',
2 'gnunet-search.c',
3 dependencies: [libgnunetfs_dep,
4 libgnunetutil_dep],
5 include_directories: [incdir, configuration_inc],
6 install: true,
7 install_dir: get_option('bindir'))
8executable ('gnunet-unindex',
9 'gnunet-unindex.c',
10 dependencies: [libgnunetfs_dep,
11 libgnunetutil_dep],
12 include_directories: [incdir, configuration_inc],
13 install: true,
14 install_dir: get_option('bindir'))
15executable ('gnunet-auto-share',
16 'gnunet-auto-share.c',
17 dependencies: [libgnunetfs_dep,
18 libgnunetutil_dep],
19 include_directories: [incdir, configuration_inc],
20 install: true,
21 install_dir: get_option('bindir'))
22executable ('gnunet-directory',
23 'gnunet-directory.c',
24 dependencies: [libgnunetfs_dep,
25 libgnunetutil_dep],
26 include_directories: [incdir, configuration_inc],
27 install: true,
28 install_dir: get_option('bindir'))
29executable ('gnunet-download',
30 'gnunet-download.c',
31 dependencies: [libgnunetfs_dep,
32 libgnunetutil_dep],
33 include_directories: [incdir, configuration_inc],
34 install: true,
35 install_dir: get_option('bindir'))
36executable ('gnunet-fs',
37 'gnunet-fs.c',
38 dependencies: [libgnunetfs_dep,
39 libgnunetutil_dep],
40 include_directories: [incdir, configuration_inc],
41 install: true,
42 install_dir: get_option('bindir'))
43executable ('gnunet-publish',
44 'gnunet-publish.c',
45 dependencies: [libgnunetfs_dep,
46 libgnunetidentity_dep,
47 libgnunetutil_dep],
48 include_directories: [incdir, configuration_inc],
49 install: true,
50 install_dir: get_option('bindir'))
51
diff --git a/src/cli/gns/.gitignore b/src/cli/gns/.gitignore
new file mode 100644
index 000000000..23bd1d13b
--- /dev/null
+++ b/src/cli/gns/.gitignore
@@ -0,0 +1,2 @@
1gnunet-gns
2gnunet-gns-proxy-setup-ca
diff --git a/src/cli/gns/Makefile.am b/src/cli/gns/Makefile.am
new file mode 100644
index 000000000..ae167bca5
--- /dev/null
+++ b/src/cli/gns/Makefile.am
@@ -0,0 +1,108 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgdata_DATA = \
5 gnunet-gns-proxy-ca.template
6
7if USE_COVERAGE
8 AM_CFLAGS = --coverage -O0
9endif
10
11if HAVE_LIBIDN
12 LIBIDN= -lidn
13else
14 LIBIDN=
15endif
16
17if HAVE_LIBIDN2
18 LIBIDN2= -lidn2
19else
20 LIBIDN2=
21endif
22
23pkgcfgdir = $(pkgdatadir)/config.d/
24
25libexecdir= $(pkglibdir)/libexec/
26
27plugindir = $(libdir)/gnunet
28
29bin_PROGRAMS = \
30 gnunet-gns
31
32bin_SCRIPTS = \
33 gnunet-gns-proxy-setup-ca
34
35gnunet-gns-proxy-setup-ca: gnunet-gns-proxy-setup-ca.in Makefile
36 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/gnunet-gns-proxy-setup-ca.in > gnunet-gns-proxy-setup-ca
37 @chmod +x gnunet-gns-proxy-setup-ca
38
39test_gnunet_gns.sh: test_gnunet_gns.sh.in Makefile
40 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/test_gnunet_gns.sh.in > test_gnunet_gns.sh
41 @chmod +x test_gnunet_gns.sh
42
43CLEANFILES = test_gnunet_gns.sh
44
45gnunet_gns_SOURCES = \
46 gnunet-gns.c
47gnunet_gns_LDADD = \
48 $(top_builddir)/src/service/gns/libgnunetgns.la \
49 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
50 $(top_builddir)/src/service/identity/libgnunetidentity.la \
51 $(top_builddir)/src/lib/util/libgnunetutil.la \
52 $(LIBIDN) $(LIBIDN2) \
53 $(GN_LIBINTL)
54
55check_SCRIPTS = \
56 test_gns_lookup.sh \
57 test_gns_config_lookup.sh \
58 test_gns_ipv6_lookup.sh\
59 test_gns_txt_lookup.sh\
60 test_gns_caa_lookup.sh\
61 test_gns_mx_lookup.sh \
62 test_gns_gns2dns_lookup.sh \
63 test_gns_gns2dns_zkey_lookup.sh \
64 test_gns_gns2dns_cname_lookup.sh \
65 test_gns_dht_lookup.sh\
66 test_gns_delegated_lookup.sh \
67 test_gns_at_lookup.sh\
68 test_gns_zkey_lookup.sh\
69 test_gns_rel_expiration.sh\
70 test_gns_soa_lookup.sh\
71 test_gns_revocation.sh\
72 test_gns_redirect_lookup.sh
73
74EXTRA_DIST = \
75 test_gns_defaults.conf \
76 test_gns_lookup.conf \
77 test_gns_simple_lookup.conf \
78 openssl.cnf \
79 gnunet-gns-proxy-setup-ca.in \
80 zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \
81 zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \
82 zonefiles/test_zonekey \
83 test_gns_lookup.sh \
84 test_gns_config_lookup.sh \
85 test_gns_ipv6_lookup.sh\
86 test_gns_txt_lookup.sh\
87 test_gns_caa_lookup.sh\
88 test_gns_mx_lookup.sh \
89 test_gns_gns2dns_lookup.sh \
90 test_gns_gns2dns_zkey_lookup.sh \
91 test_gns_gns2dns_cname_lookup.sh \
92 test_gns_dht_lookup.sh\
93 test_gns_delegated_lookup.sh \
94 test_gns_at_lookup.sh\
95 test_gns_zkey_lookup.sh\
96 test_gns_rel_expiration.sh\
97 test_gns_soa_lookup.sh\
98 test_gns_revocation.sh\
99 test_gns_redirect_lookup.sh\
100 $(pkgdata_DATA) \
101 test_gnunet_gns.sh.in
102
103if ENABLE_TEST_RUN
104if HAVE_SQLITE
105 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
106 TESTS = $(check_SCRIPTS)
107endif
108endif
diff --git a/src/cli/gns/gnunet-gns-proxy-ca.template b/src/cli/gns/gnunet-gns-proxy-ca.template
new file mode 100644
index 000000000..b1a0d16fd
--- /dev/null
+++ b/src/cli/gns/gnunet-gns-proxy-ca.template
@@ -0,0 +1,303 @@
1# X.509 Certificate options
2#
3# DN options
4
5# The organization of the subject.
6organization = "GNU"
7
8# The organizational unit of the subject.
9unit = "GNUnet"
10
11# The locality of the subject.
12locality = World
13
14# The state of the certificate owner.
15# state = "Attiki"
16
17# The country of the subject. Two letter code.
18country = ZZ
19
20# The common name of the certificate owner.
21cn = "GNS Proxy CA"
22
23# A user id of the certificate owner.
24#uid = "clauper"
25
26# Set domain components
27#dc = "name"
28#dc = "domain"
29
30# If the supported DN OIDs are not adequate you can set
31# any OID here.
32# For example set the X.520 Title and the X.520 Pseudonym
33# by using OID and string pairs.
34#dn_oid = "2.5.4.12 Dr."
35#dn_oid = "2.5.4.65 jackal"
36
37# This is deprecated and should not be used in new
38# certificates.
39# pkcs9_email = "none@none.org"
40
41# An alternative way to set the certificate's distinguished name directly
42# is with the "dn" option. The attribute names allowed are:
43# C (country), street, O (organization), OU (unit), title, CN (common name),
44# L (locality), ST (state), placeOfBirth, gender, countryOfCitizenship,
45# countryOfResidence, serialNumber, telephoneNumber, surName, initials,
46# generationQualifier, givenName, pseudonym, dnQualifier, postalCode, name,
47# businessCategory, DC, UID, jurisdictionOfIncorporationLocalityName,
48# jurisdictionOfIncorporationStateOrProvinceName,
49# jurisdictionOfIncorporationCountryName, XmppAddr, and numeric OIDs.
50
51#dn = "cn = Nikos,st = New\, Something,C=GR,surName=Mavrogiannopoulos,2.5.4.9=Arkadias"
52
53# The serial number of the certificate
54# The value is in decimal (e.g. 1963) or hex (e.g. 0x07ab).
55# Comment the field for a random serial number.
56#serial = 007
57
58# In how many days, counting from today, this certificate will expire.
59# Use -1 if there is no expiration date.
60expiration_days = 3650
61
62# Alternatively you may set concrete dates and time. The GNU date string
63# formats are accepted. See:
64# https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
65
66#activation_date = "2004-02-29 16:21:42"
67#expiration_date = "2025-02-29 16:24:41"
68
69# X.509 v3 extensions
70
71# A dnsname in case of a WWW server.
72#dns_name = "www.none.org"
73#dns_name = "www.morethanone.org"
74
75# An othername defined by an OID and a hex encoded string
76#other_name = "1.3.6.1.5.2.2 302ca00d1b0b56414e5245494e2e4f5247a11b3019a006020400000002a10f300d1b047269636b1b0561646d696e"
77#other_name_utf8 = "1.2.4.5.6 A UTF8 string"
78#other_name_octet = "1.2.4.5.6 A string that will be encoded as ASN.1 octet string"
79
80# Allows writing an XmppAddr Identifier
81#xmpp_name = juliet@im.example.com
82
83# Names used in PKINIT
84#krb5_principal = user@REALM.COM
85#krb5_principal = HTTP/user@REALM.COM
86
87# A subject alternative name URI
88#uri = "https://www.example.com"
89
90# An IP address in case of a server.
91#ip_address = "192.168.1.1"
92
93# An email in case of a person
94email = "bounce@gnunet.org"
95
96# TLS feature (rfc7633) extension. That can is used to indicate mandatory TLS
97# extension features to be provided by the server. In practice this is used
98# to require the Status Request (extid: 5) extension from the server. That is,
99# to require the server holding this certificate to provide a stapled OCSP response.
100# You can have multiple lines for multiple TLS features.
101
102# To ask for OCSP status request use:
103#tls_feature = 5
104
105# Challenge password used in certificate requests
106challenge_password = 123456
107
108# Password when encrypting a private key
109#password = secret
110
111# An URL that has CRLs (certificate revocation lists)
112# available. Needed in CA certificates.
113#crl_dist_points = "https://www.getcrl.crl/getcrl/"
114
115# Whether this is a CA certificate or not
116ca
117
118# Subject Unique ID (in hex)
119#subject_unique_id = 00153224
120
121# Issuer Unique ID (in hex)
122#issuer_unique_id = 00153225
123
124#### Key usage
125
126# The following key usage flags are used by CAs and end certificates
127
128# Whether this certificate will be used to sign data (needed
129# in TLS DHE ciphersuites). This is the digitalSignature flag
130# in RFC5280 terminology.
131signing_key
132
133# Whether this certificate will be used to encrypt data (needed
134# in TLS RSA ciphersuites). Note that it is preferred to use different
135# keys for encryption and signing. This is the keyEncipherment flag
136# in RFC5280 terminology.
137encryption_key
138
139# Whether this key will be used to sign other certificates. The
140# keyCertSign flag in RFC5280 terminology.
141cert_signing_key
142
143# Whether this key will be used to sign CRLs. The
144# cRLSign flag in RFC5280 terminology.
145#crl_signing_key
146
147# The keyAgreement flag of RFC5280. It's purpose is loosely
148# defined. Not use it unless required by a protocol.
149#key_agreement
150
151# The dataEncipherment flag of RFC5280. It's purpose is loosely
152# defined. Not use it unless required by a protocol.
153#data_encipherment
154
155# The nonRepudiation flag of RFC5280. It's purpose is loosely
156# defined. Not use it unless required by a protocol.
157#non_repudiation
158
159#### Extended key usage (key purposes)
160
161# The following extensions are used in an end certificate
162# to clarify its purpose. Some CAs also use it to indicate
163# the types of certificates they are purposed to sign.
164
165
166# Whether this certificate will be used for a TLS client;
167# this sets the id-kp-clientAuth (1.3.6.1.5.5.7.3.2) of
168# extended key usage.
169#tls_www_client
170
171# Whether this certificate will be used for a TLS server;
172# this sets the id-kp-serverAuth (1.3.6.1.5.5.7.3.1) of
173# extended key usage.
174tls_www_server
175
176# Whether this key will be used to sign code. This sets the
177# id-kp-codeSigning (1.3.6.1.5.5.7.3.3) of extended key usage
178# extension.
179#code_signing_key
180
181# Whether this key will be used to sign OCSP data. This sets the
182# id-kp-OCSPSigning (1.3.6.1.5.5.7.3.9) of extended key usage extension.
183#ocsp_signing_key
184
185# Whether this key will be used for time stamping. This sets the
186# id-kp-timeStamping (1.3.6.1.5.5.7.3.8) of extended key usage extension.
187#time_stamping_key
188
189# Whether this key will be used for email protection. This sets the
190# id-kp-emailProtection (1.3.6.1.5.5.7.3.4) of extended key usage extension.
191#email_protection_key
192
193# Whether this key will be used for IPsec IKE operations (1.3.6.1.5.5.7.3.17).
194#ipsec_ike_key
195
196## adding custom key purpose OIDs
197
198# for microsoft smart card logon
199# key_purpose_oid = 1.3.6.1.4.1.311.20.2.2
200
201# for email protection
202# key_purpose_oid = 1.3.6.1.5.5.7.3.4
203
204# for any purpose (must not be used in intermediate CA certificates)
205# key_purpose_oid = 2.5.29.37.0
206
207### end of key purpose OIDs
208
209### Adding arbitrary extensions
210# This requires to provide the extension OIDs, as well as the extension data in
211# hex format. The following two options are available since GnuTLS 3.5.3.
212#add_extension = "1.2.3.4 0x0AAB01ACFE"
213
214# As above but encode the data as an octet string
215#add_extension = "1.2.3.4 octet_string(0x0AAB01ACFE)"
216
217# For portability critical extensions shouldn't be set to certificates.
218#add_critical_extension = "5.6.7.8 0x1AAB01ACFE"
219
220# When generating a certificate from a certificate
221# request, then honor the extensions stored in the request
222# and store them in the real certificate.
223#honor_crq_extensions
224
225# Alternatively only specific extensions can be copied.
226#honor_crq_ext = 2.5.29.17
227#honor_crq_ext = 2.5.29.15
228
229# Path length constraint. Sets the maximum number of
230# certificates that can be used to certify this certificate.
231# (i.e. the certificate chain length)
232#path_len = -1
233#path_len = 2
234
235# OCSP URI
236# ocsp_uri = https://my.ocsp.server/ocsp
237
238# CA issuers URI
239# ca_issuers_uri = https://my.ca.issuer
240
241# Certificate policies
242#policy1 = 1.3.6.1.4.1.5484.1.10.99.1.0
243#policy1_txt = "This is a long policy to summarize"
244#policy1_url = https://www.example.com/a-policy-to-read
245
246#policy2 = 1.3.6.1.4.1.5484.1.10.99.1.1
247#policy2_txt = "This is a short policy"
248#policy2_url = https://www.example.com/another-policy-to-read
249
250# The number of additional certificates that may appear in a
251# path before the anyPolicy is no longer acceptable.
252#inhibit_anypolicy_skip_certs 1
253
254# Name constraints
255
256# DNS
257#nc_permit_dns = example.com
258#nc_exclude_dns = test.example.com
259
260# EMAIL
261#nc_permit_email = "nmav@ex.net"
262
263# Exclude subdomains of example.com
264#nc_exclude_email = .example.com
265
266# Exclude all e-mail addresses of example.com
267#nc_exclude_email = example.com
268
269# IP
270#nc_permit_ip = 192.168.0.0/16
271#nc_exclude_ip = 192.168.5.0/24
272#nc_permit_ip = fc0a:eef2:e7e7:a56e::/64
273
274
275# Options for proxy certificates
276#proxy_policy_language = 1.3.6.1.5.5.7.21.1
277
278
279# Options for generating a CRL
280
281# The number of days the next CRL update will be due.
282# next CRL update will be in 43 days
283#crl_next_update = 43
284
285# this is the 5th CRL by this CA
286# The value is in decimal (e.g. 1963) or hex (e.g. 0x07ab).
287# Comment the field for a time-based number.
288# Time-based CRL numbers generated in GnuTLS 3.6.3 and later
289# are significantly larger than those generated in previous
290# versions. Since CRL numbers need to be monotonic, you need
291# to specify the CRL number here manually if you intend to
292# downgrade to an earlier version than 3.6.3 after publishing
293# the CRL as it is not possible to specify CRL numbers greater
294# than 2**63-2 using hex notation in those versions.
295#crl_number = 5
296
297# Specify the update dates more precisely.
298#crl_this_update_date = "2004-02-29 16:21:42"
299#crl_next_update_date = "2025-02-29 16:24:41"
300
301# The date that the certificates will be made seen as
302# being revoked.
303#crl_revocation_date = "2025-02-29 16:24:41"
diff --git a/src/cli/gns/gnunet-gns-proxy-setup-ca.in b/src/cli/gns/gnunet-gns-proxy-setup-ca.in
new file mode 100644
index 000000000..b3ebfd11d
--- /dev/null
+++ b/src/cli/gns/gnunet-gns-proxy-setup-ca.in
@@ -0,0 +1,339 @@
1#!/bin/sh
2#
3# This shell script will generate an X509 certificate for
4# your gnunet-gns-proxy and install it (for both GNUnet
5# and your browser).
6#
7# TODO: Implement support for more browsers
8# TODO: Debug and switch to the new version
9# TODO - The only remaining task is fixing the getopts
10# TODO: Error checks
11#
12# The current version partially reuses and recycles
13# code from build.sh by NetBSD (although not entirely
14# used because it needs debugging):
15#
16# Copyright (c) 2001-2011 The NetBSD Foundation, Inc.
17# All rights reserved.
18#
19# This code is derived from software contributed to
20# The NetBSD Foundation by Todd Vierling and Luke Mewburn.
21#
22# Redistribution and use in source and binary forms, with or
23# without modification, are permitted provided that the following
24# conditions are met:
25# 1. Redistributions of source code must retain the above
26# copyright notice, this list of conditions and the following
27# disclaimer.
28# 2. Redistributions in binary form must reproduce the above
29# copyright notice, this list of conditions and the following
30# disclaimer in the documentation and/or other materials
31# provided with the distribution.
32#
33# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
34# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
35# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37# DISCLAIMED.
38# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR
39# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
41# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44# LIABILITY, OR TORT
45# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
46# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
47# OF SUCH DAMAGE.
48
49dir=$(dirname "$0")
50
51progname=${0##*/}
52
53existence() {
54 command -v "$1" >/dev/null 2>&1
55}
56
57statusmsg()
58{
59 ${runcmd} echo "${tab}$@" | tee -a "${results}"
60}
61
62infomsg()
63{
64 if [ x$verbosity = x1 ]; then
65 statusmsg "INFO:${tab}$@"
66 fi
67}
68
69warningmsg()
70{
71 statusmsg "WARNING:${tab}$@"
72}
73
74errormsg()
75{
76 statusmsg "ERROR:${tab}$@"
77}
78
79linemsg()
80{
81 statusmsg "========================================="
82}
83
84
85print_version()
86{
87 GNUNET_ARM_VERSION=`gnunet-arm -v | awk '{print $2 " " $3}'`
88 echo ${progname} $GNUNET_ARM_VERSION
89}
90
91# Whitespace normalization without depending on shell features:
92tab=' '
93tab2=' '
94nl='
95'
96
97setdefaults()
98{
99 verbosity=0
100 resfile=
101 results=/dev/null
102 tmpdir=${TMPDIR:-/tmp}
103 runcmd=
104}
105
106usage()
107{
108 if [ -n "$*" ]; then
109 echo "${nl}${progname}: $*"
110 fi
111 cat <<_usage_
112
113Usage: ${progname} [-hvVto] [-c FILE]
114
115Options:
116${tab}-c FILE Use the configuration file FILE.
117${tab}-h${tab2}${tab2}Print this help message.
118${tab}-o${tab2}${tab2}Display summary of statusmessages
119${tab}-t${tab2}${tab2}Short developer test on binaries
120${tab}-v${tab2}${tab2}Print the version and exit.
121${tab}-V${tab2}${tab2}be verbose
122
123_usage_
124 exit 1
125}
126
127
128generate_ca()
129{
130 echo ""
131 infomsg "Generating CA"
132 TMPDIR=${TMPDIR:-/tmp}
133 if test -e "$TMPDIR"; then
134 GNSCERT=`mktemp -t cert.pem.XXXXXXXX` || exit 1
135 GNSCAKY=`mktemp -t caky.pem.XXXXXXXX` || exit 1
136 GNSCANO=`mktemp -t cano.pem.XXXXXXXX` || exit 1
137 else
138 # This warning is mostly pointless.
139 warningmsg "You need to export the TMPDIR variable"
140 fi
141
142 # # ------------- gnutls
143 #
144 # if ! which certutil > /dev/null
145 # then
146 # warningmsg "The 'certutil' command was not found."
147 # warningmsg "Not importing into browsers."
148 # warningmsg "For 'certutil' install nss."
149 # else
150 # # Generate CA key
151 # # pkcs#8 password-protects key
152 # certtool --pkcs8 --generate-privkey --sec-param high --outfile ca-key.pem
153 # # self-sign the CA to create public certificate
154 # certtool --generate-self-signed --load-privkey ca-key.pem --template ca.cfg --outfile ca.pem
155
156 # ------------- openssl
157
158 GNUTLS_CA_TEMPLATE=@PKGDATADIRECTORY@/gnunet-gns-proxy-ca.template
159 OPENSSLCFG=@PKGDATADIRECTORY@/openssl.cnf
160 CERTTOOL=""
161 OPENSSL=0
162 if test -x $(existence gnunet-certtool)
163 # if test -z "`gnutls-certtool --version`" > /dev/null
164 then
165 # We only support gnutls certtool for now. Treat the grep
166 # for "gnutls" in the output with extra care, it only matches
167 # the email address! It is probably safer to run strings(1)
168 # over certtool for a string matching "gnutls"
169 if test -z "`certtool --version | grep gnutls`" > /dev/null
170 then
171 warningmsg "'gnutls-certtool' or 'certtool' command not found. Trying openssl."
172 # if test -z "`openssl version`" > /dev/null
173 if test -x $(existence openssl)
174 then
175 OPENSSL=1
176 else
177 warningmsg "Install either gnutls certtool or openssl for certificate generation!"
178 statusmsg "Cleaning up."
179 rm -f $GNSCAKY $GNSCERT
180 exit 1
181 fi
182 fi
183 CERTTOOL="certtool"
184 else
185 CERTTOOL="gnutls-certtool"
186 fi
187 if test -n "${GNUNET_CONFIG_FILE}"; then
188 GNUNET_CONFIG="-c ${GNUNET_CONFIG_FILE}"
189 else
190 GNUNET_CONFIG=""
191 fi
192 GNS_CA_CERT_PEM=`gnunet-config ${GNUNET_CONFIG} -s gns-proxy -o PROXY_CACERT -f ${options}`
193 mkdir -p `dirname $GNS_CA_CERT_PEM`
194
195 if test 1 -eq $OPENSSL
196 then
197 if test 1 -eq $verbosity; then
198 openssl req -config $OPENSSLCFG -new -x509 -days 3650 -extensions v3_ca -keyout $GNSCAKY -out $GNSCERT -subj "/C=ZZ/L=World/O=GNU/OU=GNUnet/CN=GNS Proxy CA/emailAddress=bounce@gnunet.org" -passout pass:"GNU Name System"
199 else
200 openssl req -config $OPENSSLCFG -new -x509 -days 3650 -extensions v3_ca -keyout $GNSCAKY -out $GNSCERT -subj "/C=ZZ/L=World/O=GNU/OU=GNUnet/CN=GNS Proxy CA/emailAddress=bounce@gnunet.org" -passout pass:"GNU Name System" >/dev/null 2>&1
201 fi
202 infomsg "Removing passphrase from key"
203 if test 1 -eq $verbosity; then
204 openssl rsa -passin pass:"GNU Name System" -in $GNSCAKY -out $GNSCANO
205 else
206 openssl rsa -passin pass:"GNU Name System" -in $GNSCAKY -out $GNSCANO >/dev/null 2>&1
207 fi
208 cat $GNSCERT $GNSCANO > $GNS_CA_CERT_PEM
209 else
210 if test 1 -eq $verbosity; then
211 $CERTTOOL --generate-privkey --outfile $GNSCAKY
212 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $GNSCAKY --outfile $GNSCERT
213 else
214 $CERTTOOL --generate-privkey --outfile $GNSCAKY >/dev/null 2>&1
215 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $GNSCAKY --outfile $GNSCERT >/dev/null 2>&1
216 fi
217 infomsg "Making private key available to gnunet-gns-proxy"
218 cat $GNSCERT $GNSCAKY > $GNS_CA_CERT_PEM
219 fi
220}
221
222importbrowsers()
223{
224 # if test -z "`command -v certutil`" > /dev/null 2>&1
225 if test -x $(existence gnutls-certutil) || test -x $(existence certutil)
226 then
227 statusmsg "Importing CA into browsers"
228 # TODO: Error handling?
229 for f in ~/.mozilla/firefox/*.*/
230 do
231 if [ -d $f ]; then
232 infomsg "Importing CA into Firefox at $f"
233 # delete old certificate (if any)
234 certutil -D -n "GNS Proxy CA" -d "$f" >/dev/null 2>/dev/null
235 # add new certificate
236 certutil -A -n "GNS Proxy CA" -t CT,, -d "$f" < $GNSCERT
237 fi
238 done
239 for f in ~/.mozilla/icecat/*.*/
240 do
241 if [ -d $f ]; then
242 infomsg "Importing CA into Icecat at $f"
243 # delete old certificate (if any)
244 certutil -D -n "GNS Proxy CA" -d "$f" >/dev/null 2>/dev/null
245 # add new certificate
246 certutil -A -n "GNS Proxy CA" -t CT,, -d "$f" < $GNSCERT
247 fi
248 done
249 # TODO: Error handling?
250 if [ -d ~/.pki/nssdb/ ]; then
251 statusmsg "Importing CA into Chrome at ~/.pki/nssdb/"
252 # delete old certificate (if any)
253 certutil -D -n "GNS Proxy CA" -d ~/.pki/nssdb/ >/dev/null 2>/dev/null
254 # add new certificate
255 certutil -A -n "GNS Proxy CA" -t CT,, -d ~/.pki/nssdb/ < $GNSCERT
256 fi
257 else
258 warningmsg "The 'certutil' command was not found."
259 warningmsg "Not importing into browsers."
260 warningmsg "For 'certutil' install nss."
261 fi
262}
263
264clean_up()
265{
266 infomsg "Cleaning up."
267 rm -f $GNSCAKY $GNSCANO $GNSCERT
268 if test -e $SETUP_TMPDIR
269 then
270 rm -rf $SETUP_TMPDIR
271 fi
272
273 linemsg
274 statusmsg "You can now start gnunet-gns-proxy."
275 statusmsg "Afterwards, configure your browser "
276 statusmsg "to use a SOCKS proxy on port 7777. "
277 linemsg
278}
279
280main()
281{
282 setdefaults
283 while getopts "vhVtoc:" opt; do
284 case $opt in
285 v)
286 print_version
287 exit 0
288 ;;
289 h)
290 usage
291 ;;
292 V)
293 verbosity=1
294 ;;
295 c)
296 options="$options -c $OPTARG"
297 infomsg "Using configuration file $OPTARG"
298 GNUNET_CONFIG_FILE=${OPTARG}
299 ;;
300 t)
301 verbosity=1
302 infomsg "Running short developer test"
303 if test -x $(existence openssl); then
304 openssl version
305 fi
306 if test -x $(existence certtool); then
307 certtool --version
308 fi
309 if test -x $(existence gnutls-certtool); then
310 gnutls-certtool --version
311 fi
312 exit 0
313 ;;
314 o)
315 resfile=$(mktemp -t ${progname}.results)
316 results="${resfile}"
317 ;;
318 \?)
319 echo "Invalid option: -$OPTARG" >&2
320 usage
321 ;;
322 :)
323 echo "Option -$OPTARG requires an argument." >&2
324 usage
325 ;;
326 esac
327 done
328 generate_ca
329 importbrowsers
330 if [ -s "${results}" ]; then
331 echo "===> Summary of results:"
332 sed -e 's/^===>//;s/^/ /' "${results}"
333 echo "===> ."
334 infomsg "Please remove ${results} manually."
335 fi
336 clean_up
337}
338
339main "$@"
diff --git a/src/cli/gns/gnunet-gns.c b/src/cli/gns/gnunet-gns.c
new file mode 100644
index 000000000..724fbce24
--- /dev/null
+++ b/src/cli/gns/gnunet-gns.c
@@ -0,0 +1,411 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2013, 2017-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 * @file gnunet-gns.c
22 * @brief command line tool to access distributed GNS
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#if HAVE_LIBIDN2
27#if HAVE_IDN2_H
28#include <idn2.h>
29#elif HAVE_IDN2_IDN2_H
30#include <idn2/idn2.h>
31#endif
32#elif HAVE_LIBIDN
33#if HAVE_IDNA_H
34#include <idna.h>
35#elif HAVE_IDN_IDNA_H
36#include <idn/idna.h>
37#endif
38#endif
39#include <gnunet_util_lib.h>
40#include <gnunet_gnsrecord_lib.h>
41#include <gnunet_namestore_service.h>
42#include <gnunet_gns_service.h>
43
44
45/**
46 * Configuration we are using.
47 */
48static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50/**
51 * Handle to GNS service.
52 */
53static struct GNUNET_GNS_Handle *gns;
54
55/**
56 * GNS name to lookup. (-u option)
57 */
58static char *lookup_name;
59
60/**
61 * DNS IDNA name to lookup. (set if -d option is set)
62 */
63char *idna_name;
64
65/**
66 * DNS compatibility (name is given as DNS name, possible IDNA).
67 */
68static int dns_compat;
69
70/**
71 * record type to look up (-t option)
72 */
73static char *lookup_type;
74
75/**
76 * raw output
77 */
78static int raw;
79
80/**
81 * Desired record type.
82 */
83static uint32_t rtype;
84
85/**
86 * Timeout for lookup
87 */
88static struct GNUNET_TIME_Relative timeout;
89
90/**
91 * Timeout task
92 */
93static struct GNUNET_SCHEDULER_Task *to_task;
94
95/**
96 * Handle to lookup request
97 */
98static struct GNUNET_GNS_LookupWithTldRequest *lr;
99
100/**
101 * Global return value.
102 * 0 on success (default),
103 * 1 on internal failures
104 * 2 on launch failure,
105 * 4 if the name is not a GNS-supported TLD,
106 */
107static int global_ret;
108
109
110/**
111 * Task run on shutdown. Cleans up everything.
112 *
113 * @param cls unused
114 */
115static void
116do_shutdown (void *cls)
117{
118 (void) cls;
119 if (NULL != to_task)
120 {
121 GNUNET_SCHEDULER_cancel (to_task);
122 to_task = NULL;
123 }
124 if (NULL != lr)
125 {
126 GNUNET_GNS_lookup_with_tld_cancel (lr);
127 lr = NULL;
128 }
129 if (NULL != gns)
130 {
131 GNUNET_GNS_disconnect (gns);
132 gns = NULL;
133 }
134 if (NULL != idna_name)
135 {
136 GNUNET_free (idna_name);
137 idna_name = NULL;
138 }
139}
140
141
142/**
143 * Task to run on timeout
144 *
145 * @param cls unused
146 */
147static void
148do_timeout (void*cls)
149{
150 to_task = NULL;
151 global_ret = 3; // Timeout
152 GNUNET_SCHEDULER_shutdown ();
153}
154
155
156/**
157 * Function called with the result of a GNS lookup.
158 *
159 * @param cls the 'const char *' name that was resolved
160 * @param was_gns #GNUNET_NO if TLD did not indicate use of GNS
161 * @param rd_count number of records returned
162 * @param rd array of @a rd_count records with the results
163 */
164static void
165process_lookup_result (void *cls,
166 int was_gns,
167 uint32_t rd_count,
168 const struct GNUNET_GNSRECORD_Data *rd)
169{
170 struct GNUNET_TIME_Relative block_exp;
171 const char *typename;
172 char *string_val;
173
174 lr = NULL;
175 if (GNUNET_NO == was_gns)
176 {
177 global_ret = 4; /* not for GNS */
178 GNUNET_SCHEDULER_shutdown ();
179 return;
180 }
181 block_exp = GNUNET_TIME_absolute_get_remaining (
182 GNUNET_GNSRECORD_record_get_expiration_time (
183 rd_count,
184 rd,
185 GNUNET_TIME_UNIT_ZERO_ABS));
186 if (! raw)
187 {
188 printf ("<<< %u record(s) found:\n\n", rd_count);
189 }
190 for (uint32_t i = 0; i < rd_count; i++)
191 {
192 typename = GNUNET_GNSRECORD_number_to_typename (rd[i].
193 record_type);
194 string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type
195 ,
196 rd[i].data,
197 rd[i].data_size);
198 if (NULL == string_val)
199 {
200 fprintf (stderr,
201 "Record %u of type %d malformed, skipping\n",
202 (unsigned int) i,
203 (int) rd[i].record_type);
204 continue;
205 }
206 if (raw)
207 printf ("%s\n", string_val);
208 else
209 printf ("%s: `%s' %s\n",
210 typename,
211 string_val,
212 (0 != (rd[i].flags
213 &
214 GNUNET_GNSRECORD_RF_SUPPLEMENTAL)
215 ) ?
216 "(supplemental)" : "");
217 GNUNET_free (string_val);
218 }
219 if (! raw)
220 {
221 if (0 != rd_count)
222 printf ("\nRecord set expires in %s.\n",
223 GNUNET_STRINGS_relative_time_to_string (
224 block_exp, GNUNET_YES));
225 }
226 GNUNET_SCHEDULER_shutdown ();
227}
228
229
230/**
231 * Main function that will be run.
232 *
233 * @param cls closure
234 * @param args remaining command-line arguments
235 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
236 * @param c configuration
237 */
238static void
239run (void *cls,
240 char *const *args,
241 const char *cfgfile,
242 const struct GNUNET_CONFIGURATION_Handle *c)
243{
244 const char *effective_lookup_type;
245 (void) cls;
246 (void) args;
247 (void) cfgfile;
248
249 cfg = c;
250 to_task = NULL;
251 {
252 char *colon;
253
254 if (NULL != (colon = strchr (lookup_name, ':')))
255 *colon = '\0';
256 }
257
258 /**
259 * If DNS compatibility is requested, we first verify that the
260 * lookup_name is in a DNS format. If yes, we convert it to UTF-8.
261 */
262 if (GNUNET_YES == dns_compat)
263 {
264 Idna_rc rc;
265
266 if (GNUNET_OK != GNUNET_DNSPARSER_check_name (lookup_name))
267 {
268 fprintf (stderr,
269 _ ("`%s' is not a valid DNS domain name\n"),
270 lookup_name);
271 global_ret = 3;
272 return;
273 }
274 if (IDNA_SUCCESS !=
275 (rc = idna_to_unicode_8z8z (lookup_name, &idna_name,
276 IDNA_ALLOW_UNASSIGNED)))
277 {
278 fprintf (stderr,
279 _ (
280 "Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
281 lookup_name,
282 idna_strerror (rc));
283 global_ret = 4;
284 return;
285 }
286 lookup_name = idna_name;
287 }
288
289 if (GNUNET_YES !=
290 GNUNET_CLIENT_test (cfg,
291 "arm"))
292 {
293 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
294 _ (
295 "Cannot resolve using GNS: GNUnet peer not running\n"));
296 global_ret = 5;
297 return;
298 }
299 to_task = GNUNET_SCHEDULER_add_delayed (timeout,
300 &do_timeout,
301 NULL);
302 gns = GNUNET_GNS_connect (cfg);
303 if (NULL == gns)
304 {
305 fprintf (stderr,
306 _ ("Failed to connect to GNS\n"));
307 global_ret = 2;
308 return;
309 }
310 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
311 NULL);
312 if (NULL != lookup_type)
313 {
314 effective_lookup_type = lookup_type;
315 rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
316 }
317 else
318 {
319 effective_lookup_type = "A";
320 rtype = GNUNET_DNSPARSER_TYPE_A;
321 }
322 if (UINT32_MAX == rtype)
323 {
324 fprintf (stderr,
325 _ ("Invalid typename specified, assuming `ANY'\n"));
326 rtype = GNUNET_GNSRECORD_TYPE_ANY;
327 }
328 if (! raw)
329 {
330 printf (">>> Looking for `%s' records under `%s'\n",
331 effective_lookup_type, lookup_name);
332 }
333 lr = GNUNET_GNS_lookup_with_tld (gns,
334 lookup_name,
335 rtype,
336 GNUNET_GNS_LO_DEFAULT,
337 &process_lookup_result,
338 lookup_name);
339 if (NULL == lr)
340 {
341 global_ret = 2;
342 GNUNET_SCHEDULER_shutdown ();
343 return;
344 }
345}
346
347
348/**
349 * The main function for gnunet-gns.
350 *
351 * @param argc number of arguments from the command line
352 * @param argv command line arguments
353 * @return 0 ok, 1 on error
354 */
355int
356main (int argc, char *const *argv)
357{
358 timeout = GNUNET_TIME_UNIT_FOREVER_REL;
359 struct GNUNET_GETOPT_CommandLineOption options[] =
360 { GNUNET_GETOPT_option_mandatory (
361 GNUNET_GETOPT_option_string ('u',
362 "lookup",
363 "NAME",
364 gettext_noop (
365 "Lookup a record for the given name"),
366 &lookup_name)),
367 GNUNET_GETOPT_option_string ('t',
368 "type",
369 "TYPE",
370 gettext_noop (
371 "Specify the type of the record to lookup"),
372 &lookup_type),
373 GNUNET_GETOPT_option_relative_time ('T',
374 "timeout",
375 "TIMEOUT",
376 gettext_noop (
377 "Specify a timeout for the lookup"),
378 &timeout),
379 GNUNET_GETOPT_option_flag ('r',
380 "raw",
381 gettext_noop ("No unneeded output"),
382 &raw),
383 GNUNET_GETOPT_option_flag ('d',
384 "dns",
385 gettext_noop (
386 "DNS Compatibility: Name is passed in IDNA instead of UTF-8"),
387 &dns_compat),
388 GNUNET_GETOPT_OPTION_END };
389 int ret;
390
391 if (GNUNET_OK !=
392 GNUNET_STRINGS_get_utf8_args (argc, argv,
393 &argc, &argv))
394 return 2;
395
396 GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
397 ret = GNUNET_PROGRAM_run (argc,
398 argv,
399 "gnunet-gns",
400 _ ("GNUnet GNS resolver tool"),
401 options,
402 &run,
403 NULL);
404 GNUNET_free_nz ((void *) argv);
405 if (GNUNET_OK != ret)
406 return 1;
407 return global_ret;
408}
409
410
411/* end of gnunet-gns.c */
diff --git a/src/cli/gns/meson.build b/src/cli/gns/meson.build
new file mode 100644
index 000000000..bb6bfc477
--- /dev/null
+++ b/src/cli/gns/meson.build
@@ -0,0 +1,69 @@
1configure_file(input : 'gnunet-gns-proxy-setup-ca.in',
2 output : 'gnunet-gns-proxy-setup-ca',
3 configuration : cdata,
4 install: true,
5 install_mode: 'rwxr-xr-x',
6 install_dir: get_option('bindir'))
7
8install_data('gnunet-gns-proxy-ca.template',
9 install_dir: get_option('datadir')/'gnunet')
10install_data('openssl.cnf',
11 install_dir: get_option('datadir')/'gnunet')
12
13executable ('gnunet-gns',
14 'gnunet-gns.c',
15 dependencies: [libgnunetgns_dep,
16 libgnunetgnsrecord_dep,
17 idn_dep,
18 libgnunetutil_dep],
19 include_directories: [incdir, configuration_inc],
20 install: true,
21 install_dir: get_option('bindir'))
22
23testgns = [
24 'test_dns2gns',
25 'test_gns_at_lookup',
26 'test_gns_caa_lookup',
27 'test_gns_config_lookup',
28 'test_gns_delegated_lookup',
29 'test_gns_dht_lookup',
30 'test_gns_gns2dns_cname_lookup',
31 'test_gns_gns2dns_lookup',
32 'test_gns_gns2dns_zkey_lookup',
33 'test_gns_ipv6_lookup',
34 'test_gns_lookup',
35 'test_gns_mx_lookup',
36 'test_gns_quickupdate',
37 'test_gns_redirect_lookup',
38 'test_gns_rel_expiration',
39 'test_gns_revocation',
40 'test_gns_soa_lookup',
41 'test_gns_txt_lookup',
42 'test_gns_zkey_lookup',
43 'test_gns_sbox_simple',
44 'test_gns_sbox',
45 'test_gns_box_sbox',
46 ]
47
48testconfigs = [
49 'test_dns2gns.conf',
50 'test_gns_defaults.conf',
51 'test_gns_lookup.conf',
52 'test_gns_lookup_peer1.conf',
53 'test_gns_lookup_peer2.conf',
54 'test_gns_simple_lookup.conf'
55 ]
56
57foreach f : testconfigs
58 configure_file(input: f, output: f, copy: true)
59endforeach
60
61foreach t : testgns
62
63 test_filename = t + '.sh'
64 test_file = configure_file(input : test_filename,
65 output : test_filename,
66 copy: true)
67
68 test(t, test_file, suite: 'gns', workdir: meson.current_build_dir(), is_parallel: false)
69endforeach
diff --git a/src/cli/gns/openssl.cnf b/src/cli/gns/openssl.cnf
new file mode 100644
index 000000000..5dce35388
--- /dev/null
+++ b/src/cli/gns/openssl.cnf
@@ -0,0 +1,244 @@
1#
2# OpenSSL example configuration file.
3# This is mostly being used for generation of certificate requests.
4#
5
6# This definition stops the following lines choking if HOME isn't
7# defined.
8HOME = .
9#RANDFILE = $ENV::HOME/.rnd
10
11# Extra OBJECT IDENTIFIER info:
12#oid_file = $ENV::HOME/.oid
13oid_section = new_oids
14
15# To use this configuration file with the "-extfile" option of the
16# "openssl x509" utility, name here the section containing the
17# X.509v3 extensions to use:
18# extensions =
19# (Alternatively, use a configuration file that has only
20# X.509v3 extensions in its main [= default] section.)
21
22[ new_oids ]
23
24# We can add new OIDs in here for use by 'ca' and 'req'.
25# Add a simple OID like this:
26# testoid1=1.2.3.4
27# Or use config file substitution like this:
28# testoid2=${testoid1}.5.6
29
30####################################################################
31[ ca ]
32default_ca = CA_default # The default ca section
33
34####################################################################
35[ CA_default ]
36
37dir = ./demoCA # Where everything is kept
38certs = $dir/certs # Where the issued certs are kept
39crl_dir = $dir/crl # Where the issued crl are kept
40database = $dir/index.txt # database index file.
41new_certs_dir = $dir/newcerts # default place for new certs.
42
43certificate = $dir/cacert.pem # The CA certificate
44serial = $dir/serial # The current serial number
45crl = $dir/crl.pem # The current CRL
46private_key = $dir/private/cakey.pem# The private key
47RANDFILE = $dir/private/.rand # private random number file
48
49x509_extensions = usr_cert # The extensions to add to the cert
50
51# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
52# so this is commented out by default to leave a V1 CRL.
53# crl_extensions = crl_ext
54
55default_days = 365 # how long to certify for
56default_crl_days= 30 # how long before next CRL
57default_md = md5 # which md to use.
58preserve = no # keep passed DN ordering
59
60# A few difference way of specifying how similar the request should look
61# For type CA, the listed attributes must be the same, and the optional
62# and supplied fields are just that :-)
63policy = policy_match
64
65# For the CA policy
66[ policy_match ]
67countryName = match
68stateOrProvinceName = match
69organizationName = match
70organizationalUnitName = optional
71commonName = supplied
72emailAddress = optional
73
74# For the 'anything' policy
75# At this point in time, you must list all acceptable 'object'
76# types.
77[ policy_anything ]
78countryName = optional
79stateOrProvinceName = optional
80localityName = optional
81organizationName = optional
82organizationalUnitName = optional
83commonName = supplied
84emailAddress = optional
85
86####################################################################
87[ req ]
88default_bits = 1024
89default_keyfile = privkey.pem
90distinguished_name = req_distinguished_name
91attributes = req_attributes
92x509_extensions = v3_ca # The extensions to add to the self signed cert
93
94# Passwords for private keys if not present they will be prompted for
95# input_password = secret
96# output_password = secret
97
98# This sets a mask for permitted string types. There are several options.
99# default: PrintableString, T61String, BMPString.
100# pkix : PrintableString, BMPString.
101# utf8only: only UTF8Strings.
102# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
103# MASK:XXXX a literal mask value.
104# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
105# so use this option with caution!
106string_mask = nombstr
107
108# req_extensions = v3_req # The extensions to add to a certificate request
109
110[ req_distinguished_name ]
111countryName = Country Name (2 letter code)
112countryName_default = AU
113countryName_min = 2
114countryName_max = 2
115
116stateOrProvinceName = State or Province Name (full name)
117stateOrProvinceName_default = Some-State
118
119localityName = Locality Name (eg, city)
120
1210.organizationName = Organization Name (eg, company)
1220.organizationName_default = Internet Widgits Pty Ltd
123
124# we can do this but it is not needed normally :-)
125#1.organizationName = Second Organization Name (eg, company)
126#1.organizationName_default = World Wide Web Pty Ltd
127
128organizationalUnitName = Organizational Unit Name (eg, section)
129#organizationalUnitName_default =
130
131commonName = Common Name (eg, YOUR name)
132commonName_max = 64
133
134emailAddress = Email Address
135emailAddress_max = 40
136
137# SET-ex3 = SET extension number 3
138
139[ req_attributes ]
140challengePassword = A challenge password
141challengePassword_min = 4
142challengePassword_max = 20
143
144unstructuredName = An optional company name
145
146[ usr_cert ]
147
148# These extensions are added when 'ca' signs a request.
149
150# This goes against PKIX guidelines but some CAs do it and some software
151# requires this to avoid interpreting an end user certificate as a CA.
152
153basicConstraints=CA:FALSE
154
155# Here are some examples of the usage of nsCertType. If it is omitted
156# the certificate can be used for anything *except* object signing.
157
158# This is OK for an SSL server.
159# nsCertType = server
160
161# For an object signing certificate this would be used.
162# nsCertType = objsign
163
164# For normal client use this is typical
165# nsCertType = client, email
166
167# and for everything including object signing:
168# nsCertType = client, email, objsign
169
170# This is typical in keyUsage for a client certificate.
171# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
172
173# This will be displayed in Netscape's comment listbox.
174nsComment = "OpenSSL Generated Certificate"
175
176# PKIX recommendations harmless if included in all certificates.
177subjectKeyIdentifier=hash
178authorityKeyIdentifier=keyid,issuer:always
179
180# This stuff is for subjectAltName and issuerAltname.
181# Import the email address.
182# subjectAltName=email:copy
183
184# Copy subject details
185# issuerAltName=issuer:copy
186
187#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
188#nsBaseUrl
189#nsRevocationUrl
190#nsRenewalUrl
191#nsCaPolicyUrl
192#nsSslServerName
193
194[ v3_req ]
195
196# Extensions to add to a certificate request
197
198basicConstraints = CA:FALSE
199keyUsage = nonRepudiation, digitalSignature, keyEncipherment
200
201[ v3_ca ]
202
203
204# Extensions for a typical CA
205
206
207# PKIX recommendation.
208
209subjectKeyIdentifier=hash
210
211authorityKeyIdentifier=keyid:always,issuer:always
212
213# This is what PKIX recommends but some broken software chokes on critical
214# extensions.
215#basicConstraints = critical,CA:true
216# So we do this instead.
217basicConstraints = CA:true
218
219# Key usage: this is typical for a CA certificate. However since it will
220# prevent it being used as an test self-signed certificate it is best
221# left out by default.
222# keyUsage = cRLSign, keyCertSign
223
224# Some might want this also
225# nsCertType = sslCA, emailCA
226
227# Include email address in subject alt name: another PKIX recommendation
228# subjectAltName=email:copy
229# Copy issuer details
230# issuerAltName=issuer:copy
231
232# DER hex encoding of an extension: beware experts only!
233# obj=DER:02:03
234# Where 'obj' is a standard or added object
235# You can even override a supported extension:
236# basicConstraints= critical, DER:30:03:01:01:FF
237
238[ crl_ext ]
239
240# CRL extensions.
241# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
242
243# issuerAltName=issuer:copy
244authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/src/cli/gns/test_dns2gns.conf b/src/cli/gns/test_dns2gns.conf
new file mode 100644
index 000000000..2f6bdc797
--- /dev/null
+++ b/src/cli/gns/test_dns2gns.conf
@@ -0,0 +1,69 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = YES
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
8
9[dht]
10START_ON_DEMAND = YES
11IMMEDIATE_START = YES
12
13[gns]
14# PREFIX = valgrind --leak-check=full --track-origins=yes
15START_ON_DEMAND = YES
16AUTO_IMPORT_PKEY = YES
17MAX_PARALLEL_BACKGROUND_QUERIES = 10
18DEFAULT_LOOKUP_TIMEOUT = 15 s
19RECORD_PUT_INTERVAL = 1 h
20ZONE_PUBLISH_TIME_WINDOW = 1 h
21.gnunet.org =
22
23[namestore]
24IMMEDIATE_START = YES
25#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
26
27[revocation]
28WORKBITS = 1
29
30[dhtcache]
31QUOTA = 1 MB
32DATABASE = heap
33
34[topology]
35TARGET-CONNECTION-COUNT = 16
36AUTOCONNECT = YES
37FRIENDS-ONLY = NO
38MINIMUM-FRIENDS = 0
39
40[ats]
41WAN_QUOTA_IN = 1 GB
42WAN_QUOTA_OUT = 1 GB
43
44[transport]
45plugins = tcp
46NEIGHBOUR_LIMIT = 50
47PORT = 2091
48
49[transport-tcp]
50TIMEOUT = 300 s
51
52[nat]
53DISABLEV6 = YES
54BINDTO = 127.0.0.1
55ENABLE_UPNP = NO
56BEHIND_NAT = NO
57ALLOW_NAT = NO
58INTERNAL_ADDRESS = 127.0.0.1
59EXTERNAL_ADDRESS = 127.0.0.1
60
61[dns2gns]
62BINARY = gnunet-dns2gns
63START_ON_DEMAND = YES
64IMMEDIATE_START = YES
65RUN_PER_USER = YES
66BIND_TO = 127.0.0.1
67BIND_TO6 = ::1
68PORT = 12000
69OPTIONS = -d 1.1.1.1
diff --git a/src/cli/gns/test_dns2gns.sh b/src/cli/gns/test_dns2gns.sh
new file mode 100755
index 000000000..a6024ca3c
--- /dev/null
+++ b/src/cli/gns/test_dns2gns.sh
@@ -0,0 +1,52 @@
1#!/bin/bash
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_dns2gns.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
19MY_EGO="localego"
20TEST_IP="127.0.0.1"
21TEST_IPV6="dead::beef"
22LABEL="fnord"
23TEST_DOMAIN="taler.net"
24
25gnunet-arm -s -c test_dns2gns.conf
26PKEY=`gnunet-identity -V -C $MY_EGO -c test_dns2gns.conf`
27gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t A -V $TEST_IP -e 3600s -c test_dns2gns.conf
28gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t AAAA -V $TEST_IPV6 -e 3600s -c test_dns2gns.conf
29
30# FIXME resolution works but always returns all available records
31# also, the records seem to be returned twice if using GNS
32
33if nslookup -port=12000 $LABEL.$PKEY localhost && nslookup -port=12000 $LABEL.$MY_EGO localhost; then
34 echo "PASS: GNS records can be resolved using dns2gns bridge"
35else
36 echo "FAIL: GNS records can't be resolved using dns2gns bridge"
37 gnunet-arm -e -c test_dns2gns.conf
38 rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
39 exit 1
40fi
41
42if nslookup -port=12000 $TEST_DOMAIN localhost; then
43 echo "PASS: DNS records can be resolved using dns2gns bridge"
44else
45 echo "FAIL: DNS records can't be resolved using dns2gns bridge"
46 gnunet-arm -e -c test_dns2gns.conf
47 rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
48 exit 1
49fi
50gnunet-arm -e -c test_dns2gns.conf
51
52rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
diff --git a/src/cli/gns/test_gns_at_lookup.sh b/src/cli/gns/test_gns_at_lookup.sh
new file mode 100755
index 000000000..6a2c958de
--- /dev/null
+++ b/src/cli/gns/test_gns_at_lookup.sh
@@ -0,0 +1,41 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19
20TEST_IP="127.0.0.1"
21MY_EGO="myego"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C delegatedego -c test_gns_lookup.conf
24DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep delegatedego | awk '{print $3}')
25gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
26gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
27gnunet-namestore -p -z delegatedego -a -n '@' -t A -V $TEST_IP -e never -c test_gns_lookup.conf
28sleep 0.5
29RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u b.$MY_EGO -t A -c test_gns_lookup.conf`
30gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
31gnunet-namestore -z delegatedego -d -n '@' -t A -V $TEST_IP -e never -c test_gns_lookup.conf
32gnunet-arm -e -c test_gns_lookup.conf
33rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
34
35if [ "$RES_IP" = "$TEST_IP" ]
36then
37 exit 0
38else
39 echo "Failed to resolve to proper IP, got $RES_IP."
40 exit 1
41fi
diff --git a/src/cli/gns/test_gns_box_sbox.sh b/src/cli/gns/test_gns_box_sbox.sh
new file mode 100755
index 000000000..d7e95912e
--- /dev/null
+++ b/src/cli/gns/test_gns_box_sbox.sh
@@ -0,0 +1,59 @@
1#!/bin/bash
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_B="TXT_record_in_BOX"
20TEST_S="TXT_record_in_SBOX"
21TEST_A="10.1.11.10"
22MY_EGO="myego"
23LABEL="testsbox"
24SERVICE="443"
25SERVICE_TEXT="_443"
26PROTOCOL="6"
27PROTOCOL_TEXT="_tcp"
28gnunet-arm -s -c test_gns_lookup.conf
29gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
30gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 16 $TEST_S" -e never -c test_gns_lookup.conf
31gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 16 $TEST_B" -e never -c test_gns_lookup.conf
32gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
33gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 1 $TEST_A" -e never -c test_gns_lookup.conf
34sleep 0.5
35RES_B_S=`$DO_TIMEOUT gnunet-gns --raw -u $SERVICE_TEXT.$PROTOCOL_TEXT.$LABEL.$MY_EGO -t TXT -c test_gns_lookup.conf`
36RES_A=`$DO_TIMEOUT gnunet-gns --raw -u $SERVICE_TEXT.$PROTOCOL_TEXT.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
37gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 16 $TEST_S" -e never -c test_gns_lookup.conf
38gnunet-namestore -z $MY_EGO -d -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 16 $TEST_B" -e never -c test_gns_lookup.conf
39gnunet-namestore -p -z $MY_EGO -d -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
40gnunet-namestore -p -z $MY_EGO -d -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 1 $TEST_A" -e never -c test_gns_lookup.conf
41gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
42gnunet-arm -e -c test_gns_lookup.conf
43rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
44
45{ read RES_A1; read RES_A2; read RES_B; read RES_S;} <<< "${RES_B_S}"
46if [ "$RES_B" = "$RES_S" ]
47then
48 echo "Failed to resolve to diffrent TXT records, got '$RES_B' and '$RES_S'."
49 exit 1
50fi
51
52{ read RES_S_A; read RES_B_A;} <<< "${RES_A}"
53if [ "$RES_S_A" = "$TEST_A" ] && [ "$RES_B_A" = "$TEST_A" ]
54then
55 exit 0
56else
57 echo "Failed to resolve to proper A '$TEST_A', got '$RES_S_A' and '$RES_S_B'."
58 exit 1
59fi
diff --git a/src/cli/gns/test_gns_caa_lookup.sh b/src/cli/gns/test_gns_caa_lookup.sh
new file mode 100755
index 000000000..fb488f47b
--- /dev/null
+++ b/src/cli/gns/test_gns_caa_lookup.sh
@@ -0,0 +1,38 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_CAA="0 issue ca.example.net; policy=ev"
20MY_EGO="myego"
21LABEL="testcaa"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t CAA -V "$TEST_CAA" -e never -c test_gns_lookup.conf
25sleep 0.5
26RES_CAA=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t CAA -c test_gns_lookup.conf`
27gnunet-namestore -z $MY_EGO -d -n $LABEL -t CAA -V "$TEST_CAA" -e never -c test_gns_lookup.conf
28gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
29gnunet-arm -e -c test_gns_lookup.conf
30rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
31
32if [ "$RES_CAA" = "$TEST_CAA" ]
33then
34 exit 0
35else
36 echo "Failed to resolve to proper CAA, got '$RES_CAA'."
37 exit 1
38fi
diff --git a/src/cli/gns/test_gns_config_lookup.sh b/src/cli/gns/test_gns_config_lookup.sh
new file mode 100755
index 000000000..bda08f87b
--- /dev/null
+++ b/src/cli/gns/test_gns_config_lookup.sh
@@ -0,0 +1,44 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16MY_EGO="myego"
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f`
19CFG=`mktemp --tmpdir=$PWD`
20cp test_gns_lookup.conf $CFG || exit 77
21which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
22TEST_IP="dead::beef"
23gnunet-arm -s -c $CFG || exit 77
24gnunet-identity -C $MY_EGO -c $CFG
25EPUB=`gnunet-identity -d -c $CFG | grep $MY_EGO | awk '{print $3}'`
26gnunet-arm -e -c $CFG
27gnunet-config -c $CFG -s "gns" -o ".google.com" -V $EPUB
28gnunet-arm -s -c $CFG
29sleep 1
30gnunet-namestore -p -z $MY_EGO -a -n www -t AAAA -V $TEST_IP -e never -c $CFG
31RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.google.com -t AAAA -c $CFG`
32gnunet-namestore -z $MY_EGO -d -n www -t AAAA -V $TEST_IP -e never -c $CFG
33gnunet-identity -D $MY_EGO -c $CFG
34gnunet-arm -e -c $CFG
35rm -rf `gnunet-config -c $CFG -f -s paths -o GNUNET_TEST_HOME`
36rm $CFG
37
38if [ "$RES_IP" = "$TEST_IP" ]
39then
40 exit 0
41else
42 echo "Failed to resolve to proper IP, got $RES_IP."
43 exit 1
44fi
diff --git a/src/cli/gns/test_gns_defaults.conf b/src/cli/gns/test_gns_defaults.conf
new file mode 100644
index 000000000..80a2f3c44
--- /dev/null
+++ b/src/cli/gns/test_gns_defaults.conf
@@ -0,0 +1,34 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-testing/
3
4[namestore-sqlite]
5FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
6
7[namecache-sqlite]
8FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db
9
10[identity]
11# Directory where we store information about our egos
12EGODIR = $GNUNET_TEST_HOME/identity/egos/
13
14[dhtcache]
15DATABASE = heap
16
17[transport]
18PLUGINS = tcp
19
20[transport-tcp]
21BINDTO = 127.0.0.1
22
23
24[fs]
25IMMEDIATE_START = NO
26START_ON_DEMAND = NO
27
28[rps]
29IMMEDIATE_START = NO
30START_ON_DEMAND = NO
31
32[topology]
33IMMEDIATE_START = NO
34START_ON_DEMAND = NO
diff --git a/src/cli/gns/test_gns_delegated_lookup.sh b/src/cli/gns/test_gns_delegated_lookup.sh
new file mode 100755
index 000000000..5105abdb5
--- /dev/null
+++ b/src/cli/gns/test_gns_delegated_lookup.sh
@@ -0,0 +1,45 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19MY_EGO="myego"
20OTHER_EGO="delegatedego"
21FINAL_LABEL="www"
22DELEGATION_LABEL="b"
23
24TEST_IP="127.0.0.1"
25gnunet-arm -s -c test_gns_lookup.conf
26gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
27DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
28gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
29gnunet-namestore -p -z $MY_EGO -a -n $DELEGATION_LABEL -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
30gnunet-namestore -p -z $OTHER_EGO -a -n $FINAL_LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
31sleep 0.5
32RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $FINAL_LABEL.$DELEGATION_LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
33gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
34gnunet-namestore -z $OTHER_EGO -d -n $FINAL_LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
35gnunet-arm -e -c test_gns_lookup.conf
36
37rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
38
39if [ "$RES_IP" = "$TEST_IP" ]
40then
41 exit 0
42else
43 echo "Failed to resolve to proper IP, got $RES_IP."
44 exit 1
45fi
diff --git a/src/cli/gns/test_gns_dht_lookup.sh b/src/cli/gns/test_gns_dht_lookup.sh
new file mode 100755
index 000000000..da87d8477
--- /dev/null
+++ b/src/cli/gns/test_gns_dht_lookup.sh
@@ -0,0 +1,63 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18TEST_IP="127.0.0.1"
19MY_EGO="myego"
20OTHER_EGO="delegatedego"
21
22rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
23gnunet-arm -s -c test_gns_lookup.conf
24gnunet-arm -i zonemaster -c test_gns_lookup.conf
25gnunet-arm -i datastore -c test_gns_lookup.conf
26gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
27DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
28gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
29echo "MYEGO: $MY_EGO OTHER_EGO: $DELEGATED_PKEY"
30gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
31#This works
32gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
33#This doesn't
34gnunet-namestore -p -z $OTHER_EGO -a -n www2 -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
35sleep 6
36#gnunet-namestore -p -z $OTHER_EGO -d -n www2 -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
37#gnunet-namestore -p -z $OTHER_EGO -a -n www2 -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
38gnunet-arm -k zonemaster -c test_gns_lookup.conf
39gnunet-arm -i zonemaster -c test_gns_lookup.conf
40#gnunet-arm -r -c test_gns_lookup.conf
41#gnunet-arm -i zonemaster
42#gnunet-arm -i gns -c test_gns_lookup.conf
43#gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
44#gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
45#gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
46RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
47RES_IP_REL=`$DO_TIMEOUT gnunet-gns --raw -u www2.b.$MY_EGO -t A -c test_gns_lookup.conf`
48#gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
49gnunet-arm -e -c test_gns_lookup.conf
50rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
51
52if [ "$RES_IP_REL" != "$TEST_IP" ]
53then
54 echo "Failed to resolve to proper IP, got $RES_IP_REL. (relative expiration)"
55 #exit 1
56fi
57if [ "$RES_IP" = "$TEST_IP" ]
58then
59 exit 0
60else
61 echo "Failed to resolve to proper IP, got $RES_IP."
62 exit 1
63fi
diff --git a/src/cli/gns/test_gns_gns2dns_cname_lookup.sh b/src/cli/gns/test_gns_gns2dns_cname_lookup.sh
new file mode 100755
index 000000000..c33c9d132
--- /dev/null
+++ b/src/cli/gns/test_gns_gns2dns_cname_lookup.sh
@@ -0,0 +1,98 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18# IP address of 'www.gnunet.org'
19TEST_IP="147.87.255.218"
20# IP address of 'gnunet.org'
21TEST_IPALT="131.159.74.67"
22# IPv6 address of 'gnunet.org'
23TEST_IP6="2a07:6b47:100:464::9357:ffdb"
24
25# main label used during resolution
26TEST_RECORD_NAME="homepage"
27
28XNS=ns.joker.com
29
30if ! nslookup gnunet.org a.$XNS > /dev/null 2>&1
31then
32 echo "Cannot reach DNS, skipping test"
33 exit 77
34fi
35
36# helper record for pointing to the DNS resolver
37TEST_RESOLVER_LABEL="resolver"
38# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
39# using the TEST_RESOLVER_LABEL DNS server for resolution
40TEST_RECORD_GNS2DNS1="gnunet.org@a.$XNS"
41TEST_RECORD_GNS2DNS2="gnunet.org@b.$XNS"
42TEST_RECORD_GNS2DNS3="gnunet.org@c.$XNS"
43
44MY_EGO="myego"
45# various names we will use for resolution
46TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
47
48which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
49
50gnunet-arm -s -c test_gns_lookup.conf
51OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
52echo $OUT | grep $TEST_IP - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv4 for gnunet.org not found ($OUT), skipping test"; exit 77; }
53echo $OUT | grep $TEST_IP6 - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv6 for gnunet.org not found ($OUT), skipping test"; exit 77; }
54
55
56gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
57
58# set IP address for DNS resolver for resolving in gnunet.org domain
59# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
60gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS1 -e never -c test_gns_lookup.conf
61gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS2 -e never -c test_gns_lookup.conf
62gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS3 -e never -c test_gns_lookup.conf
63
64gnunet-namestore -z $MY_EGO -D -c test_gns_lookup.conf
65
66sleep 0.5
67
68# lookup 'www.gnunet.org', IPv4
69RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
70# lookup 'www.gnunet.org', IPv6
71RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf`
72
73# clean up
74gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS1 -e never -c test_gns_lookup.conf
75gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS2 -e never -c test_gns_lookup.conf
76gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS3 -e never -c test_gns_lookup.conf
77gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
78gnunet-arm -e -c test_gns_lookup.conf
79rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
80
81ret=0
82if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
83then
84 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
85else
86 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
87 ret=1
88fi
89
90if echo "$RES_IP6" | grep "$TEST_IP6" > /dev/null
91then
92 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
93else
94 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
95 ret=1
96fi
97
98exit $ret
diff --git a/src/cli/gns/test_gns_gns2dns_lookup.sh b/src/cli/gns/test_gns_gns2dns_lookup.sh
new file mode 100755
index 000000000..43a4756d3
--- /dev/null
+++ b/src/cli/gns/test_gns_gns2dns_lookup.sh
@@ -0,0 +1,117 @@
1#!/bin/sh
2trap "gnunet-arm -e -c test_gns_lookup.conf" INT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
17# IP address of 'docs.gnunet.org'
18TEST_IP_ALT2="147.87.255.218"
19# IP address of 'www.gnunet.org'
20TEST_IP="147.87.255.218"
21# IPv6 address of 'gnunet.org'
22TEST_IP6="2a07:6b47:100:464::9357:ffdb"
23# permissive DNS resolver we will use for the test
24TEST_IP_GNS2DNS="8.8.8.8"
25
26# main label used during resolution
27TEST_RECORD_NAME="homepage"
28
29if ! nslookup gnunet.org $TEST_IP_GNS2DNS > /dev/null 2>&1
30then
31 echo "Cannot reach DNS, skipping test"
32 exit 77
33fi
34
35# helper record for pointing to the DNS resolver
36TEST_RESOLVER_LABEL="resolver"
37# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
38# using the TEST_RESOLVER_LABEL DNS server for resolution
39TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.+"
40
41MY_EGO="myego"
42# various names we will use for resolution
43TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
44TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.$MY_EGO"
45TEST_DOMAIN_ALT2="docs.${TEST_RECORD_NAME}.$MY_EGO"
46
47which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
48
49
50gnunet-arm -s -c test_gns_lookup.conf
51
52OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
53echo $OUT | grep $TEST_IP - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv4 for gnunet.org not found ($OUT), skipping test"; exit 77; }
54echo $OUT | grep $TEST_IP6 - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv6 for gnunet.org not found ($OUT), skipping test"; exit 77; }
55
56
57
58gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
59
60# set IP address for DNS resolver for resolving in gnunet.org domain
61gnunet-namestore -p -z $MY_EGO -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
62# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
63gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
64
65sleep 1
66
67gnunet-gns -u $TEST_RECORD_NAME.$MY_EGO -t GNS2DNS -c test_gns_lookup.conf
68
69# lookup 'www.gnunet.org', IPv4
70RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
71# lookup 'www.gnunet.org', IPv6
72RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf | head -n1`
73# lookup 'gnunet.org', IPv4
74RES_IP_ALT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT -t A -c test_gns_lookup.conf`
75# lookup 'docs.gnunet.org', IPv4
76RES_IP_ALT2=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT2 -t A -c test_gns_lookup.conf`
77
78# clean up
79gnunet-namestore -z $MY_EGO -d -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
80gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
81gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
82gnunet-arm -e -c test_gns_lookup.conf
83rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
84
85ret=0
86if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
87then
88 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
89else
90 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
91 ret=1
92fi
93
94if [ "${RES_IP6%?}" = "${TEST_IP6%?}" ]
95then
96 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
97else
98 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
99 ret=1
100fi
101
102if echo "$RES_IP_ALT" | grep "$TEST_IP" > /dev/null
103then
104 echo "PASS: Resolved $TEST_DOMAIN_ALT to $RES_IP_ALT."
105else
106 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT, got $RES_IP_ALT, wanted $TEST_IP."
107 ret=1
108fi
109
110if echo "$RES_IP_ALT2" | grep "$TEST_IP_ALT2" > /dev/null
111then
112 echo "PASS: Resolved $TEST_DOMAIN_ALT2 to $RES_IP_ALT2."
113else
114 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT2, got $RES_IP_ALT2, wanted $TEST_IP_ALT2."
115 ret=1
116fi
117exit $ret
diff --git a/src/cli/gns/test_gns_gns2dns_zkey_lookup.sh b/src/cli/gns/test_gns_gns2dns_zkey_lookup.sh
new file mode 100755
index 000000000..03549314e
--- /dev/null
+++ b/src/cli/gns/test_gns_gns2dns_zkey_lookup.sh
@@ -0,0 +1,116 @@
1#!/bin/sh
2trap "gnunet-arm -e -c test_gns_lookup.conf" INT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
17# IP address of 'docs.gnunet.org'
18TEST_IP_ALT2="147.87.255.218"
19# IP address of 'www.gnunet.org'
20TEST_IP="147.87.255.218"
21# IPv6 address of 'gnunet.org'
22TEST_IP6="2a07:6b47:100:464::9357:ffdb"
23# permissive DNS resolver we will use for the test
24TEST_IP_GNS2DNS="8.8.8.8"
25
26# main label used during resolution
27TEST_RECORD_NAME="homepage"
28
29if ! nslookup gnunet.org $TEST_IP_GNS2DNS > /dev/null 2>&1
30then
31 echo "Cannot reach DNS, skipping test"
32 exit 77
33fi
34
35# helper record for pointing to the DNS resolver
36TEST_RESOLVER_LABEL="resolver"
37
38MY_EGO="myego"
39# various names we will use for resolution
40TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
41TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.$MY_EGO"
42TEST_DOMAIN_ALT2="docs.${TEST_RECORD_NAME}.$MY_EGO"
43
44which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
45
46
47gnunet-arm -s -c test_gns_lookup.conf
48
49OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
50echo $OUT | grep $TEST_IP - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv4 for gnunet.org not found ($OUT), skipping test"; exit 77; }
51echo $OUT | grep $TEST_IP6 - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv6 for gnunet.org not found ($OUT), skipping test"; exit 77; }
52
53
54
55gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
56MY_EGO_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep ${MY_EGO} | awk '{print $3}')
57# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
58# using the TEST_RESOLVER_LABEL DNS server for resolution
59TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.${MY_EGO_PKEY}"
60
61# set IP address for DNS resolver for resolving in gnunet.org domain
62gnunet-namestore -p -z $MY_EGO -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
63# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
64gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
65
66sleep 1
67
68# lookup 'www.gnunet.org', IPv4
69RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
70# lookup 'www.gnunet.org', IPv6
71RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf | head -n1`
72# lookup 'gnunet.org', IPv4
73RES_IP_ALT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT -t A -c test_gns_lookup.conf`
74# lookup 'docs.gnunet.org', IPv4
75RES_IP_ALT2=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT2 -t A -c test_gns_lookup.conf`
76
77# clean up
78gnunet-namestore -z $MY_EGO -d -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
79gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
80gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
81gnunet-arm -e -c test_gns_lookup.conf
82rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
83
84ret=0
85if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
86then
87 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
88else
89 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
90 ret=1
91fi
92
93if [ "${RES_IP6%?}" = "${TEST_IP6%?}" ]
94then
95 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
96else
97 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
98 ret=1
99fi
100
101if echo "$RES_IP_ALT" | grep "$TEST_IP" > /dev/null
102then
103 echo "PASS: Resolved $TEST_DOMAIN_ALT to $RES_IP_ALT."
104else
105 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT, got $RES_IP_ALT, wanted $TEST_IP."
106 ret=1
107fi
108
109if echo "$RES_IP_ALT2" | grep "$TEST_IP_ALT2" > /dev/null
110then
111 echo "PASS: Resolved $TEST_DOMAIN_ALT2 to $RES_IP_ALT2."
112else
113 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT2, got $RES_IP_ALT2, wanted $TEST_IP_ALT2."
114 ret=1
115fi
116exit $ret
diff --git a/src/cli/gns/test_gns_ipv6_lookup.sh b/src/cli/gns/test_gns_ipv6_lookup.sh
new file mode 100755
index 000000000..31e662f68
--- /dev/null
+++ b/src/cli/gns/test_gns_ipv6_lookup.sh
@@ -0,0 +1,37 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16MY_EGO="myego"
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f`
19which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
20TEST_IP="dead::beef"
21gnunet-arm -s -c test_gns_lookup.conf
22gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
23gnunet-namestore -p -z $MY_EGO -a -n www -t AAAA -V $TEST_IP -e never -c test_gns_lookup.conf
24sleep 0.5
25RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.$MY_EGO -t AAAA -c test_gns_lookup.conf`
26gnunet-namestore -z $MY_EGO -d -n www -t AAAA -V $TEST_IP -e never -c test_gns_lookup.conf
27gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
28gnunet-arm -e -c test_gns_lookup.conf
29rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
30
31if [ "$RES_IP" = "$TEST_IP" ]
32then
33 exit 0
34else
35 echo "Failed to resolve to proper IP, got $RES_IP."
36 exit 1
37fi
diff --git a/src/cli/gns/test_gns_lightest.sh b/src/cli/gns/test_gns_lightest.sh
new file mode 100755
index 000000000..2d2203e66
--- /dev/null
+++ b/src/cli/gns/test_gns_lightest.sh
@@ -0,0 +1,141 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19START_EGO="startego"
20MY_EGO="test-lightest"
21LABEL="test-scheme"
22PTR_LABEL="test-ptr"
23TEST_URI="10 1 \"https://ec.europa.eu/tools/lotl/eu-lotl.xml\""
24TEST_SMIMEA="3 0 1 f7e8e4e554fb7c7a8f6f360e0ca2f59d466c8f9539a25963f5ed37e905f0c797"
25SCHEME="_scheme"
26TRUST="_trust"
27TRANSLATION="_translation"
28TEST_PTR="$SCHEME.$TRUST.$LABEL.$MY_EGO.$START_EGO"
29TEST_PTR2="$TRANSLATION.$TRUST.$LABEL.$MY_EGO.$START_EGO"
30gnunet-arm -s -c test_gns_lookup.conf
31gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
32gnunet-identity -C $START_EGO -c test_gns_lookup.conf
33PKEY=`gnunet-identity -d -e $MY_EGO -q -c test_gns_lookup.conf`
34gnunet-namestore -p -z $MY_EGO -a -n $PTR_LABEL -t BOX -V "49152 49152 12 $TEST_PTR" -e never -c test_gns_lookup.conf
35gnunet-namestore -p -z $MY_EGO -a -n $PTR_LABEL -t BOX -V "49152 49153 12 $TEST_PTR2" -e never -c test_gns_lookup.conf
36gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 256 $TEST_URI" -e never -c test_gns_lookup.conf
37gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 53 $TEST_SMIMEA" -e never -c test_gns_lookup.conf
38gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49153 256 $TEST_URI" -e never -c test_gns_lookup.conf
39gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49153 53 $TEST_SMIMEA" -e never -c test_gns_lookup.conf
40gnunet-namestore -p -z $START_EGO -a -n $MY_EGO -t PKEY -V "$PKEY" -e never -c test_gns_lookup.conf
41sleep 0.5
42PTR_SCHEME=`$DO_TIMEOUT gnunet-gns --raw -u $SCHEME.$TRUST.$PTR_LABEL.$MY_EGO.$START_EGO -t PTR -c test_gns_lookup.conf`
43PTR_TRANSLATION=`$DO_TIMEOUT gnunet-gns --raw -u $TRANSLATION.$TRUST.$PTR_LABEL.$MY_EGO.$START_EGO -t PTR -c test_gns_lookup.conf`
44
45SUCCESS=0
46if [ "$PTR_SCHEME" != "$TEST_PTR" ]
47then
48 echo "Failed to resolve to proper PTR, got '$PTR_SCHEME'."
49 SUCCESS=1
50else
51 echo "Resolved to proper PTR, got '$PTR_SCHEME'."
52fi
53
54if [ "$PTR_TRANSLATION" != "$TEST_PTR2" ]
55then
56 echo "Failed to resolve to proper PTR, got '$PTR_TRANSLATION'."
57 SUCCESS=1
58else
59 echo "Resolved to proper PTR, got '$PTR_TRANSLATION'."
60fi
61
62if [ "$SUCCESS" = "1" ]
63then
64 gnunet-namestore -z $MY_EGO -X -c test_gns_lookup.conf
65 gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
66 gnunet-arm -e -c test_gns_lookup.conf
67 rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
68 exit 1
69fi
70
71
72RES_URI_SCHEME=`$DO_TIMEOUT gnunet-gns --raw -u $PTR_SCHEME -t URI -c test_gns_lookup.conf`
73RES_SMIMEA_SCHEME=`$DO_TIMEOUT gnunet-gns --raw -u $PTR_SCHEME -t SMIMEA -c test_gns_lookup.conf`
74
75RES_URI_TRANSLATION=`$DO_TIMEOUT gnunet-gns --raw -u $PTR_TRANSLATION -t URI -c test_gns_lookup.conf`
76RES_SMIMEA_TRANSLATION=`$DO_TIMEOUT gnunet-gns --raw -u $PTR_TRANSLATION -t SMIMEA -c test_gns_lookup.conf`
77
78
79if [ "$RES_URI_SCHEME" != "$TEST_URI" ]
80then
81 echo "Failed to resolve to proper URI, got '$RES_URI_SCHEME'."
82 SUCCESS=1
83else
84 echo "Resolved to proper URI, got '$RES_URI_SCHEME'."
85fi
86
87if [ "$RES_SMIMEA_SCHEME" != "$TEST_SMIMEA" ]
88then
89 echo "Failed to resolve to proper SMIMEA, got '$RES_SMIMEA_SCHEME'."
90 SUCCESS=1
91else
92 echo "Resolved to proper SMIMEA, got '$RES_SMIMEA_SCHEME'."
93fi
94
95if [ "$RES_URI_TRANSLATION" != "$TEST_URI" ]
96then
97 echo "Failed to resolve to proper URI, got '$RES_URI_TRANSLATION'."
98 SUCCESS=1
99else
100 echo "Resolved to proper URI, got '$RES_URI_TRANSLATION'."
101fi
102
103if [ "$RES_SMIMEA_TRANSLATION" != "$TEST_SMIMEA" ]
104then
105 echo "Failed to resolve to proper SMIMEA, got '$RES_SMIMEA_TRANSLATION'."
106 SUCCESS=1
107else
108 echo "Resolved to proper SMIMEA, got '$RES_SMIMEA_TRANSLATION'."
109fi
110
111gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 256 10 1 \"thisisnotavaliduri\"" -e never -c test_gns_lookup.conf
112status=$?
113gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 256 10 1 mailto:thisrecordismalformed@test.com" -e never -c test_gns_lookup.conf
114status2=$?
115
116if [ "$status" = "0" ]
117then
118 echo "Failed to detect malformed URI."
119 SUCCESS=1
120else
121 echo "Detected malformed URI."
122fi
123
124if [ "$status2" = "0" ]
125then
126 echo "Failed to detect malformed URI Record Presentation."
127 SUCCESS=1
128else
129 echo "Detected malformed URI Presentation."
130fi
131
132
133
134gnunet-namestore -z $MY_EGO -X -c test_gns_lookup.conf
135gnunet-namestore -z $START_EGO -X -c test_gns_lookup.conf
136gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
137gnunet-identity -D $START_EGO -c test_gns_lookup.conf
138gnunet-arm -e -c test_gns_lookup.conf
139rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
140
141exit $SUCCESS \ No newline at end of file
diff --git a/src/cli/gns/test_gns_lookup.conf b/src/cli/gns/test_gns_lookup.conf
new file mode 100644
index 000000000..46e89a64d
--- /dev/null
+++ b/src/cli/gns/test_gns_lookup.conf
@@ -0,0 +1,65 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = NO
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
8
9[dht]
10START_ON_DEMAND = YES
11
12[gns]
13# PREFIX = valgrind --leak-check=full --track-origins=yes
14START_ON_DEMAND = YES
15AUTO_IMPORT_PKEY = YES
16MAX_PARALLEL_BACKGROUND_QUERIES = 10
17DEFAULT_LOOKUP_TIMEOUT = 15 s
18RECORD_PUT_INTERVAL = 1 h
19ZONE_PUBLISH_TIME_WINDOW = 1 h
20DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
21
22[namestore]
23#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
24
25[zonemaster]
26IMMEDIATE_START = YES
27START_ON_DEMAND = YES
28
29[rest]
30BASIC_AUTH_ENABLED=NO
31
32[revocation]
33WORKBITS = 2
34EPOCH_DURATION = 365 d
35
36[dhtcache]
37QUOTA = 1 MB
38DATABASE = heap
39
40[topology]
41TARGET-CONNECTION-COUNT = 16
42AUTOCONNECT = YES
43FRIENDS-ONLY = NO
44MINIMUM-FRIENDS = 0
45
46[ats]
47WAN_QUOTA_IN = 1 GB
48WAN_QUOTA_OUT = 1 GB
49
50[transport]
51plugins = tcp
52NEIGHBOUR_LIMIT = 50
53PORT = 2091
54
55[transport-tcp]
56TIMEOUT = 300 s
57
58[nat]
59DISABLEV6 = YES
60BINDTO = 127.0.0.1
61ENABLE_UPNP = NO
62BEHIND_NAT = NO
63ALLOW_NAT = NO
64INTERNAL_ADDRESS = 127.0.0.1
65EXTERNAL_ADDRESS = 127.0.0.1
diff --git a/src/cli/gns/test_gns_lookup.sh b/src/cli/gns/test_gns_lookup.sh
new file mode 100755
index 000000000..92dfae28b
--- /dev/null
+++ b/src/cli/gns/test_gns_lookup.sh
@@ -0,0 +1,37 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_IP="127.0.0.1"
20MY_EGO="myego"
21LABEL="www"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
25sleep 0.5
26RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
27gnunet-namestore -z $MY_EGO -d -n $LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
28gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
29gnunet-arm -e -c test_gns_lookup.conf
30
31if [ "$RES_IP" = "$TEST_IP" ]
32then
33 exit 0
34else
35 echo "FAIL: Failed to resolve to proper IP, got $RES_IP."
36 exit 1
37fi
diff --git a/src/cli/gns/test_gns_lookup_peer1.conf b/src/cli/gns/test_gns_lookup_peer1.conf
new file mode 100644
index 000000000..69e2f0973
--- /dev/null
+++ b/src/cli/gns/test_gns_lookup_peer1.conf
@@ -0,0 +1,75 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = YES
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
8GNUNET_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-1-system-runtime/
9GNUNET_USER_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-1-user-runtime/
10
11[dht]
12START_ON_DEMAND = YES
13IMMEDIATE_START = YES
14
15[gns]
16# PREFIX = valgrind --leak-check=full --track-origins=yes
17START_ON_DEMAND = YES
18AUTO_IMPORT_PKEY = YES
19MAX_PARALLEL_BACKGROUND_QUERIES = 10
20DEFAULT_LOOKUP_TIMEOUT = 15 s
21RECORD_PUT_INTERVAL = 1 h
22ZONE_PUBLISH_TIME_WINDOW = 1 h
23DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
24
25[namestore]
26IMMEDIATE_START = YES
27#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
28
29[revocation]
30WORKBITS = 1
31
32[dhtcache]
33QUOTA = 1 MB
34DATABASE = heap
35
36[topology]
37TARGET-CONNECTION-COUNT = 16
38AUTOCONNECT = YES
39FRIENDS-ONLY = NO
40MINIMUM-FRIENDS = 0
41
42[ats]
43WAN_QUOTA_IN = 1 GB
44WAN_QUOTA_OUT = 1 GB
45
46[transport]
47plugins = unix
48NEIGHBOUR_LIMIT = 50
49PORT = 2091
50
51[transport-unix]
52UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-transport-plugin-unix1.sock
53
54[hostlist]
55SERVERS = http://localhost:9999/
56OPTIONS = -b
57IMMEDIATE_START = YES
58
59[nat]
60DISABLEV6 = YES
61BINDTO = 127.0.0.1
62ENABLE_UPNP = NO
63BEHIND_NAT = NO
64ALLOW_NAT = NO
65INTERNAL_ADDRESS = 127.0.0.1
66EXTERNAL_ADDRESS = 127.0.0.1
67
68[dns2gns]
69BINARY = gnunet-dns2gns
70START_ON_DEMAND = YES
71IMMEDIATE_START = YES
72RUN_PER_USER = YES
73BIND_TO = 127.0.0.1
74BIND_TO6 = ::1
75OPTIONS = -d 1.1.1.1 -p 12000
diff --git a/src/cli/gns/test_gns_lookup_peer2.conf b/src/cli/gns/test_gns_lookup_peer2.conf
new file mode 100644
index 000000000..3de81d7f3
--- /dev/null
+++ b/src/cli/gns/test_gns_lookup_peer2.conf
@@ -0,0 +1,72 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = YES
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-2/
8GNUNET_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-2-runtime/
9GNUNET_USER_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-2-user-runtime/
10
11[dht]
12START_ON_DEMAND = YES
13IMMEDIATE_START = YES
14
15[identity]
16START_ON_DEMAND = YES
17IMMEDIATE_START = YES
18
19[gns]
20# PREFIX = valgrind --leak-check=full --track-origins=yes
21IMMEDIATE_START = YES
22START_ON_DEMAND = YES
23AUTO_IMPORT_PKEY = YES
24MAX_PARALLEL_BACKGROUND_QUERIES = 10
25DEFAULT_LOOKUP_TIMEOUT = 15 s
26RECORD_PUT_INTERVAL = 1 h
27ZONE_PUBLISH_TIME_WINDOW = 1 h
28DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
29
30[namestore]
31IMMEDIATE_START = YES
32#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
33
34[revocation]
35WORKBITS = 1
36
37[dhtcache]
38QUOTA = 1 MB
39DATABASE = heap
40
41[topology]
42TARGET-CONNECTION-COUNT = 16
43AUTOCONNECT = YES
44FRIENDS-ONLY = NO
45MINIMUM-FRIENDS = 0
46
47[hostlist]
48SERVERS =
49HTTPPORT = 9999
50OPTIONS = -p
51IMMEDIATE_START = YES
52
53
54[ats]
55WAN_QUOTA_IN = 1 GB
56WAN_QUOTA_OUT = 1 GB
57
58[transport]
59plugins = unix
60NEIGHBOUR_LIMIT = 50
61
62[transport-unix]
63UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-transport-plugin-unix2.sock
64
65[nat]
66DISABLEV6 = YES
67BINDTO = 127.0.0.1
68ENABLE_UPNP = NO
69BEHIND_NAT = NO
70ALLOW_NAT = NO
71INTERNAL_ADDRESS = 127.0.0.1
72EXTERNAL_ADDRESS = 127.0.0.1
diff --git a/src/cli/gns/test_gns_multiple_record_lookup.sh b/src/cli/gns/test_gns_multiple_record_lookup.sh
new file mode 100755
index 000000000..52a487329
--- /dev/null
+++ b/src/cli/gns/test_gns_multiple_record_lookup.sh
@@ -0,0 +1,95 @@
1#!/bin/bash
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup_peer1.conf" INT
4trap "gnunet-arm -e -c test_gns_lookup_peer2.conf" INT
5which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
6
7unset XDG_DATA_HOME
8unset XDG_CONFIG_HOME
9unset XDG_CACHE_HOME
10
11LOCATION=$(which gnunet-config)
12if [ -z $LOCATION ]
13then
14 LOCATION="gnunet-config"
15fi
16$LOCATION --version 1> /dev/null
17if test $? != 0
18then
19 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
20 exit 77
21fi
22
23rm -rf `gnunet-config -c test_gns_lookup_peer1.conf -f -s paths -o GNUNET_TEST_HOME`
24rm -rf `gnunet-config -c test_gns_lookup_peer2.conf -f -s paths -o GNUNET_TEST_HOME`
25OTHER_EGO="remoteego"
26
27TEST_IP="127.0.0.1"
28TEST_IPV6="dead::beef"
29LABEL="fnord"
30
31gnunet-arm -s -c test_gns_lookup_peer2.conf
32gnunet-identity -C $OTHER_EGO -c test_gns_lookup_peer2.conf
33PKEY=`$DO_TIMEOUT gnunet-identity -d -c test_gns_lookup_peer2.conf | grep $OTHER_EGO | awk '{print $3}'`
34
35# Note: if zonemaster is kept running, it MAY publish the "A" record in the
36# DHT immediately and then _LATER_ also the "AAAA" record. But as then there
37# will be TWO valid blocks in the DHT (one with only A and one with A and
38# AAAA), the subsequent GET for both may fail and only return the result with
39# just the "A" record).
40# If we _waited_ until the original block with just "A" expired, everything
41# would be fine, but we don't want to do that for the test, so we
42# simply pause publishing to the DHT until all records are defined.
43# In the future, it would be good to have an enhanced gnunet-namestore command
44# that would read a series of changes to be made to a record set from
45# stdin and do them _all_ *atomically*. Then we would not need to do this.
46
47gnunet-arm -c test_gns_lookup_peer2.conf -k zonemaster
48
49gnunet-namestore -p -z $OTHER_EGO -a -n $LABEL -t A -V $TEST_IP -e 3600s -c test_gns_lookup_peer2.conf
50gnunet-namestore -p -z $OTHER_EGO -a -n $LABEL -t AAAA -V $TEST_IPV6 -e 3600s -c test_gns_lookup_peer2.conf
51gnunet-namestore -D -z $OTHER_EGO -n $LABEL -c test_gns_lookup_peer2.conf
52
53gnunet-arm -c test_gns_lookup_peer2.conf -i zonemaster
54
55gnunet-arm -s -c test_gns_lookup_peer1.conf
56
57
58RESP=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$PKEY -t ANY -c test_gns_lookup_peer1.conf`
59RESP1=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$PKEY -t A -c test_gns_lookup_peer1.conf`
60RESP2=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$PKEY -t AAAA -c test_gns_lookup_peer1.conf`
61
62echo "$LABEL.$PKEY"
63echo $RESP $RESP1 $RESP2
64
65gnunet-arm -e -c test_gns_lookup_peer1.conf
66gnunet-arm -e -c test_gns_lookup_peer2.conf
67
68gnunet-config -c test_gns_lookup_peer1.conf -f -s paths -o GNUNET_TEST_HOME
69
70rm -rf `gnunet-config -c test_gns_lookup_peer1.conf -f -s paths -o GNUNET_TEST_HOME`
71rm -rf `gnunet-config -c test_gns_lookup_peer2.conf -f -s paths -o GNUNET_TEST_HOME`
72
73RESPONSES=($(echo $RESP | tr "\n" " " ))
74
75if [ "$RESP1" == "$TEST_IP" ]
76then
77 echo "PASS: A record resolution from DHT via separate peer"
78else
79 echo "FAIL: A record resolution from DHT via separate peer, got $RESP1, expected $TEST_IP"
80 exit 1
81fi
82if [ "$RESP2" == "$TEST_IPV6" ]
83then
84 echo "PASS: AAAA record resolution from DHT via separate peer"
85else
86 echo "FAIL: AAAA record resolution from DHT via separate peer, got $RESP2, expected $TEST_IPV6"
87 exit 1
88fi
89if [[ "${RESPONSES[0]} ${RESPONSES[1]}" == "$TEST_IPV6 $TEST_IP" ]] || [[ "${RESPONSES[0]} ${RESPONSES[1]}" == "$TEST_IP $TEST_IPV6" ]]
90then
91 echo "PASS: ANY record resolution from DHT via separate peer"
92else
93 echo "FAIL: ANY record resolution from DHT via separate peer, got $RESP, expected $TEST_IPV6 $TEST_IP or $TEST_IP $TEST_IPV6"
94 exit 1
95fi
diff --git a/src/cli/gns/test_gns_mx_lookup.sh b/src/cli/gns/test_gns_mx_lookup.sh
new file mode 100755
index 000000000..6f2b8192d
--- /dev/null
+++ b/src/cli/gns/test_gns_mx_lookup.sh
@@ -0,0 +1,44 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
19
20MY_EGO="myego"
21TEST_MX="5 mail.+"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24PKEY=`gnunet-identity -d | grep "$MY_EGO - " | awk '{print $3'}`
25WANT_MX="5 mail.$PKEY"
26gnunet-namestore -p -z $MY_EGO -a -n www -t MX -V "$TEST_MX" -e never -c test_gns_lookup.conf
27sleep 0.5
28RES_MX=`$DO_TIMEOUT gnunet-gns --raw -u www.$MY_EGO -t MX -c test_gns_lookup.conf`
29gnunet-namestore -z $MY_EGO -d -n www -t MX -V "$TEST_MX" -e never -c test_gns_lookup.conf
30gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
31gnunet-arm -e -c test_gns_lookup.conf
32rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
33
34# make cmp case-insensitive by converting to lower case first
35RES_MX=`echo $RES_MX | tr [A-Z] [a-z]`
36WANT_MX=`echo $WANT_MX | tr [A-Z] [a-z]`
37
38if [ "$RES_MX" = "$WANT_MX" ]
39then
40 exit 0
41else
42 echo "FAIL: did not get proper IP, got $RES_MX, expected $WANT_MX."
43 exit 1
44fi
diff --git a/src/cli/gns/test_gns_quickupdate.sh b/src/cli/gns/test_gns_quickupdate.sh
new file mode 100755
index 000000000..eac69103d
--- /dev/null
+++ b/src/cli/gns/test_gns_quickupdate.sh
@@ -0,0 +1,65 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17MY_EGO="myego"
18OTHER_EGO="delegatedego"
19
20
21rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
22which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
23TEST_IP="127.0.0.1"
24gnunet-arm -s -c test_gns_lookup.conf
25gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
26gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
27DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
28gnunet-arm -i gns -c test_gns_lookup.conf
29gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
30# Give GNS/namestore time to fully start and finish initial iteration
31sleep 2
32# Performing namestore update
33gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
34# Give GNS chance to observe store event via monitor
35sleep 1
36gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
37# give GNS chance to process monitor event
38sleep 1
39# stop everything and restart to check that DHT PUT did happen
40gnunet-arm -k gns -c test_gns_lookup.conf
41gnunet-arm -k namestore -c test_gns_lookup.conf
42gnunet-arm -k namecache -c test_gns_lookup.conf
43gnunet-arm -k zonemaster -c test_gns_lookup.conf
44# Purge nameacache, as we might otherwise fetch from there
45# FIXME: testcase started failing after the line below was fixed by adding '-f',
46# might have never worked (!)
47rm -r `gnunet-config -f -c test_gns_lookup.conf -s namecache-sqlite -o FILENAME`
48gnunet-arm -i namestore -c test_gns_lookup.conf
49gnunet-arm -i namecache -c test_gns_lookup.conf
50gnunet-arm -i zonemaster -c test_gns_lookup.conf
51gnunet-arm -i gns -c test_gns_lookup.conf
52RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
53gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
54gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
55gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
56gnunet-arm -e -c test_gns_lookup.conf
57rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
58
59if [ "$RES_IP" = "$TEST_IP" ]
60then
61 exit 0
62else
63 echo "Failed to properly resolve IP, expected $TEST_IP, got $RES_IP."
64 exit 1
65fi
diff --git a/src/cli/gns/test_gns_redirect_lookup.sh b/src/cli/gns/test_gns_redirect_lookup.sh
new file mode 100755
index 000000000..90729713d
--- /dev/null
+++ b/src/cli/gns/test_gns_redirect_lookup.sh
@@ -0,0 +1,100 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17# permissive DNS resolver we will use for the test
18DNS_RESOLVER="8.8.8.8"
19if ! nslookup gnunet.org $DNS_RESOLVER > /dev/null 2>&1
20then
21 echo "Cannot reach DNS, skipping test"
22 exit 77
23fi
24
25
26rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
27
28TEST_IP_PLUS="127.0.0.1"
29TEST_IP_DNS="147.87.255.218"
30TEST_RECORD_REDIRECT_SERVER="server"
31TEST_RECORD_REDIRECT_PLUS="server.+"
32TEST_RECORD_REDIRECT_DNS="gnunet.org"
33TEST_RECORD_NAME_SERVER="server"
34TEST_RECORD_NAME_PLUS="www"
35TEST_RECORD_NAME_ZKEY="www2"
36TEST_RECORD_NAME_DNS="www3"
37MY_EGO="myego"
38TEST_DOMAIN_PLUS="www.$MY_EGO"
39TEST_DOMAIN_ZKEY="www2.$MY_EGO"
40TEST_DOMAIN_DNS="www3.$MY_EGO"
41which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
42
43gnunet-arm -s -c test_gns_lookup.conf
44gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
45MY_EGO_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep ${MY_EGO} | awk '{print $3}')
46TEST_RECORD_REDIRECT_ZKEY="server.${MY_EGO_PKEY}"
47gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_DNS -t REDIRECT -V $TEST_RECORD_REDIRECT_DNS -e never -c test_gns_lookup.conf
48gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_PLUS -t REDIRECT -V $TEST_RECORD_REDIRECT_PLUS -e never -c test_gns_lookup.conf
49gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_ZKEY -t REDIRECT -V $TEST_RECORD_REDIRECT_ZKEY -e never -c test_gns_lookup.conf
50gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_REDIRECT_SERVER -t A -V $TEST_IP_PLUS -e never -c test_gns_lookup.conf
51sleep 1
52RES_REDIRECT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_PLUS -t A -c test_gns_lookup.conf`
53RES_REDIRECT_RAW=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_PLUS -t REDIRECT -c test_gns_lookup.conf`
54RES_REDIRECT_ZKEY=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ZKEY -t A -c test_gns_lookup.conf`
55RES_REDIRECT_DNS=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_DNS -t A -c test_gns_lookup.conf | grep $TEST_IP_DNS`
56
57TESTEGOZONE=`gnunet-identity -c test_gns_lookup.conf -d | awk '{print $3}'`
58gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_NAME_DNS -t REDIRECT -V $TEST_RECORD_REDIRECT_DNS -e never -c test_gns_lookup.conf
59gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_NAME_PLUS -t REDIRECT -V $TEST_RECORD_REDIRECT_PLUS -e never -c test_gns_lookup.conf
60gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_NAME_ZKEY -t REDIRECT -V $TEST_RECORD_REDIRECT_ZKEY -e never -c test_gns_lookup.conf
61gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_REDIRECT_SERVER -t A -V $TEST_IP_PLUS -e never -c test_gns_lookup.conf
62gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
63gnunet-arm -e -c test_gns_lookup.conf
64rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
65
66# make cmp case-insensitive by converting to lower case first
67RES_REDIRECT_RAW=`echo $RES_REDIRECT_RAW | tr [A-Z] [a-z]`
68TESTEGOZONE=`echo $TESTEGOZONE | tr [A-Z] [a-z]`
69if [ "$RES_REDIRECT_RAW" = "server.$TESTEGOZONE" ]
70then
71 echo "PASS: REDIRECT resolution from GNS"
72else
73 echo "FAIL: REDIRECT resolution from GNS, got $RES_REDIRECT_RAW, expected server.$TESTEGOZONE."
74 exit 1
75fi
76
77if [ "$RES_REDIRECT" = "$TEST_IP_PLUS" ]
78then
79 echo "PASS: IP resolution from GNS (.+)"
80else
81 echo "FAIL: IP resolution from GNS (.+), got $RES_REDIRECT, expected $TEST_IP_PLUS."
82 exit 1
83fi
84
85if [ "$RES_REDIRECT_ZKEY" = "$TEST_IP_PLUS" ]
86then
87 echo "PASS: IP resolution from GNS (.zkey)"
88else
89 echo "FAIL: IP resolution from GNS (.zkey), got $RES_REDIRECT, expected $TEST_IP_PLUS."
90 exit 1
91fi
92
93if echo "$RES_REDIRECT_DNS" | grep "$TEST_IP_DNS" > /dev/null
94then
95 echo "PASS: IP resolution from DNS"
96 exit 0
97else
98 echo "FAIL: IP resolution from DNS, got $RES_REDIRECT_DNS, expected $TEST_IP_DNS."
99 exit 1
100fi
diff --git a/src/cli/gns/test_gns_rel_expiration.sh b/src/cli/gns/test_gns_rel_expiration.sh
new file mode 100755
index 000000000..a240cfd0f
--- /dev/null
+++ b/src/cli/gns/test_gns_rel_expiration.sh
@@ -0,0 +1,64 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10
11if [ -z $(which timeout) ]
12then
13 echo "timeout utility not found which is required for test."
14 exit 77
15fi
16
17$LOCATION --version 1> /dev/null
18if test $? != 0
19then
20 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
21 exit 77
22fi
23
24MY_EGO="myego"
25OTHER_EGO="delegatedego"
26
27rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
28which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
29TEST_IP="127.0.0.1"
30gnunet-arm -s -c test_gns_lookup.conf
31gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
32gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
33DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
34gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
35gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
36gnunet-arm -i gns -c test_gns_lookup.conf
37sleep 0.5
38# confirm that lookup currently works
39RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
40# remove entry
41gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
42# wait for old entry with 5s 'expiration' to definitively expire
43sleep 6
44# try again, should no longer work
45RES_IP_EXP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
46gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
47gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
48gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
49gnunet-arm -e -c test_gns_lookup.conf
50rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
51
52if [ "$RES_IP_EXP" = "$TEST_IP" ]
53then
54 echo "Failed to properly expire IP, got $RES_IP_EXP."
55 exit 1
56fi
57
58if [ "$RES_IP" = "$TEST_IP" ]
59then
60 exit 0
61else
62 echo "Failed to properly resolve IP, got $RES_IP."
63 exit 1
64fi
diff --git a/src/cli/gns/test_gns_revocation.sh b/src/cli/gns/test_gns_revocation.sh
new file mode 100755
index 000000000..2253adcb4
--- /dev/null
+++ b/src/cli/gns/test_gns_revocation.sh
@@ -0,0 +1,50 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19MY_EGO="myego"
20OTHER_EGO="delegatedego"
21TEST_IP="127.0.0.1"
22
23gnunet-arm -s -c test_gns_lookup.conf
24gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
25DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
26gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
27gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
28gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
29sleep 1
30RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
31gnunet-revocation -R $OTHER_EGO -p -c test_gns_lookup.conf
32RES_IP_REV=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
33gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
34gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
35gnunet-arm -e -c test_gns_lookup.conf
36rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
37
38if [ "$RES_IP" != "$TEST_IP" ]
39then
40 echo "Failed to resolve to proper IP, got $RES_IP."
41 exit 1
42fi
43
44if [ "x$RES_IP_REV" = "x" ]
45then
46 exit 0
47else
48 echo "Failed to revoke zone, got $RES_IP_REV."
49 exit 1
50fi
diff --git a/src/cli/gns/test_gns_sbox.sh b/src/cli/gns/test_gns_sbox.sh
new file mode 100755
index 000000000..6918bf130
--- /dev/null
+++ b/src/cli/gns/test_gns_sbox.sh
@@ -0,0 +1,121 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 7"
19TEST_A="139.134.54.9"
20MY_EGO="myego"
21LABEL="testsbox"
22PREFIX1="_name"
23PREFIX2="__"
24PREFIX3="_a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_"
25PREFIX4="abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz._abc"
26PREFIX5="abc.abc._abc.abc"
27PREFIX6="abc.abc._abc.abc._abc"
28PREFIX7="abc.abc._abc.abc._abc.abc"
29PREFIX8="_at"
30gnunet-arm -s -c test_gns_lookup.conf
31gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
32gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX1 1 $TEST_A" -e never -c test_gns_lookup.conf
33gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX2 1 $TEST_A" -e never -c test_gns_lookup.conf
34gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX3 1 $TEST_A" -e never -c test_gns_lookup.conf
35gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX4 1 $TEST_A" -e never -c test_gns_lookup.conf
36gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX5 1 $TEST_A" -e never -c test_gns_lookup.conf
37gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX6 1 $TEST_A" -e never -c test_gns_lookup.conf
38gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX7 1 $TEST_A" -e never -c test_gns_lookup.conf
39gnunet-namestore -p -z $MY_EGO -a -n '@' -t SBOX -V "$PREFIX8 1 $TEST_A" -e never -c test_gns_lookup.conf
40sleep 0.5
41RES_A1=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX1.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
42RES_A2=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX2.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
43RES_A3=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX3.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
44RES_A4=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX4.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
45RES_A5=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX5.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
46RES_A6=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX6.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
47RES_A7=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX7.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
48RES_A8=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX8.$MY_EGO -t A -c test_gns_lookup.conf`
49gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX1 1 $TEST_A" -e never -c test_gns_lookup.conf
50gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX2 1 $TEST_A" -e never -c test_gns_lookup.conf
51gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX3 1 $TEST_A" -e never -c test_gns_lookup.conf
52gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX4 1 $TEST_A" -e never -c test_gns_lookup.conf
53gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX6 1 $TEST_A" -e never -c test_gns_lookup.conf
54gnunet-namestore -z $MY_EGO -d -n '@' -t SBOX -V "$PREFIX8 1 $TEST_A" -e never -c test_gns_lookup.conf
55gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
56gnunet-arm -e -c test_gns_lookup.conf
57rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
58
59if [ "$RES_A1" = "$TEST_A" ]
60then
61 exit 0
62else
63 echo "Failed to resolve to proper A, got '$RES_A1'."
64 exit 1
65fi
66
67if [ "$RES_A2" = "$TEST_A" ]
68then
69 exit 0
70else
71 echo "Failed to resolve to proper A, got '$RES_A2'."
72 exit 1
73fi
74
75if [ "$RES_A3" = "$TEST_A" ]
76then
77 exit 0
78else
79 echo "Failed to resolve to proper A, got '$RES_A3'."
80 exit 1
81fi
82
83if [ "$RES_A4" = "$TEST_A" ]
84then
85 exit 0
86else
87 echo "Failed to resolve to proper A, got '$RES_A4'."
88 exit 1
89fi
90
91if [ "$RES_A5" = "$TEST_A" ]
92then
93 echo "Should have failed to resolve to proper A, got '$RES_A5' anyway."
94 exit 1
95else
96 exit 0
97fi
98
99if [ "$RES_A6" = "$TEST_A" ]
100then
101 exit 0
102else
103 echo "Failed to resolve to proper A, got '$RES_A6'."
104 exit 1
105fi
106
107if [ "$RES_A7" = "$TEST_A" ]
108then
109 echo "Should have failed to resolve to proper A, got '$RES_A7' anyway."
110 exit 1
111else
112 exit 0
113fi
114
115if [ "$RES_A8" = "$TEST_A" ]
116then
117 exit 0
118else
119 echo "Failed to resolve to proper A, got '$RES_A8'."
120 exit 1
121fi
diff --git a/src/cli/gns/test_gns_sbox_simple.sh b/src/cli/gns/test_gns_sbox_simple.sh
new file mode 100755
index 000000000..f0d31e471
--- /dev/null
+++ b/src/cli/gns/test_gns_sbox_simple.sh
@@ -0,0 +1,39 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_A="139.134.54.9"
20MY_EGO="myego"
21HASH="c93f1e400f26708f98cb19d936620da35eec8f72e57f9eec01c1afd6"
22PROTOCOL_TEXT="_smimecert"
23gnunet-arm -s -c test_gns_lookup.conf
24gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
25gnunet-namestore -p -z $MY_EGO -a -n '@' -t SBOX -V "$HASH.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
26sleep 0.5
27RES_A=`$DO_TIMEOUT gnunet-gns --raw -u $HASH.$PROTOCOL_TEXT.$MY_EGO -t A -c test_gns_lookup.conf`
28gnunet-namestore -z $MY_EGO -d -n '@' -t SBOX -V "$HASH.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
29gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
30gnunet-arm -e -c test_gns_lookup.conf
31rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
32
33if [ "$RES_A" = "$TEST_A" ]
34then
35 exit 0
36else
37 echo "Failed to resolve to proper A, got '$RES_A'."
38 exit 1
39fi
diff --git a/src/cli/gns/test_gns_simple_lookup.conf b/src/cli/gns/test_gns_simple_lookup.conf
new file mode 100644
index 000000000..374731377
--- /dev/null
+++ b/src/cli/gns/test_gns_simple_lookup.conf
@@ -0,0 +1,97 @@
1@INLINE@ test_gns_defaults.conf
2[fs]
3START_ON_DEMAND = NO
4
5[resolver]
6START_ON_DEMAND = YES
7HOSTNAME = localhost
8
9[dht]
10START_ON_DEMAND = YES
11ACCEPT_FROM6 = ::1;
12ACCEPT_FROM = 127.0.0.1;
13HOSTNAME = localhost
14PORT = 12100
15BINARY = gnunet-service-dht
16
17[dhtcache]
18QUOTA = 1 MB
19DATABASE = heap
20
21[transport]
22PLUGINS = tcp
23ACCEPT_FROM6 = ::1;
24ACCEPT_FROM = 127.0.0.1;
25NEIGHBOUR_LIMIT = 50
26PORT = 12365
27
28[ats]
29WAN_QUOTA_IN = 1 GB
30WAN_QUOTA_OUT = 1 GB
31
32[core]
33PORT = 12092
34
35[arm]
36PORT = 12366
37
38[transport-tcp]
39TIMEOUT = 300 s
40PORT = 12368
41BINDTO = 127.0.0.1
42
43[PATHS]
44GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-gns-peer-1/
45
46
47[nat]
48DISABLEV6 = YES
49ENABLE_UPNP = NO
50BEHIND_NAT = NO
51ALLOW_NAT = NO
52INTERNAL_ADDRESS = 127.0.0.1
53EXTERNAL_ADDRESS = 127.0.0.1
54USE_LOCALADDR = NO
55
56[dns]
57START_ON_DEMAND = YES
58DNS_EXIT = 8.8.8.8
59
60[gns]
61#PREFIX = valgrind --leak-check=full --track-origins=yes
62START_ON_DEMAND = YES
63BINARY = gnunet-service-gns
64ZONEKEY = zonefiles/test_zonekey
65PRIVATE_ZONE = private
66PRIVATE_ZONEKEY = zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey
67SHORTEN_ZONE = short
68SHORTEN_ZONEKEY = zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey
69#ZONEKEY = $GNUNET_TEST_HOME/gns/zonekey.zkey
70HIJACK_DNS = NO
71UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-gns.sock
72AUTO_IMPORT_PKEY = YES
73MAX_PARALLEL_BACKGROUND_QUERIES = 10
74DEFAULT_LOOKUP_TIMEOUT = 15 s
75RECORD_PUT_INTERVAL = 1 h
76
77[nse]
78START_ON_DEMAND = NO
79
80[statistics]
81START_ON_DEMAND = NO
82
83[namestore]
84PORT = 22371
85START_ON_DEMAND = YES
86UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-namestore-default.sock
87UNIX_MATCH_UID = YES
88UNIX_MATCH_GID = YES
89HOSTNAME = localhost
90BINARY = gnunet-service-namestore
91ACCEPT_FROM = 127.0.0.1;
92ACCEPT_FROM6 = ::1;
93DATABASE = sqlite
94ZONEFILE_DIRECTORY = $GNUNET_TEST_HOME
95
96[namestore-sqlite]
97FILENAME = $GNUNET_TEST_HOME/sqlite-default.db
diff --git a/src/cli/gns/test_gns_soa_lookup.sh b/src/cli/gns/test_gns_soa_lookup.sh
new file mode 100755
index 000000000..a697782bb
--- /dev/null
+++ b/src/cli/gns/test_gns_soa_lookup.sh
@@ -0,0 +1,51 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
18
19rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
20MY_EGO="myego"
21TEST_DOMAIN="homepage.$MY_EGO"
22# some public DNS resolver we can use
23#TEST_IP_GNS2DNS="184.172.157.218" # This one seems currently down.
24TEST_IP_GNS2DNS="8.8.8.8"
25TEST_RECORD_NAME="homepage"
26TEST_RECORD_GNS2DNS="gnunet.org"
27
28if ! nslookup $TEST_RECORD_GNS2DNS $TEST_IP_GNS2DNS > /dev/null 2>&1
29then
30 echo "Cannot reach DNS, skipping test"
31 exit 77
32fi
33
34gnunet-arm -s -c test_gns_lookup.conf
35gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
36gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V ${TEST_RECORD_GNS2DNS}@${TEST_IP_GNS2DNS} -e never -c test_gns_lookup.conf
37sleep 0.5
38RES_SOA=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t SOA -c test_gns_lookup.conf`
39gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V ${TEST_RECORD_GNS2DNS}@${TEST_IP_GNS2DNS} -e never -c test_gns_lookup.conf > /dev/null 2>&1
40gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
41gnunet-arm -e -c test_gns_lookup.conf
42rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
43
44if [ "x$RES_SOA" != "x" ]
45then
46 echo "PASS: Resolved SOA for $TEST_DOMAIN to $RES_SOA."
47 exit 0
48else
49 echo "Failed to resolve to proper SOA for $TEST_DOMAIN, got no result."
50 exit 1
51fi
diff --git a/src/cli/gns/test_gns_txt_lookup.sh b/src/cli/gns/test_gns_txt_lookup.sh
new file mode 100755
index 000000000..4e36e8ad8
--- /dev/null
+++ b/src/cli/gns/test_gns_txt_lookup.sh
@@ -0,0 +1,38 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_TXT="GNS powered txt record data"
20MY_EGO="myego"
21LABEL="testtxt"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t TXT -V "$TEST_TXT" -e never -c test_gns_lookup.conf
25sleep 0.5
26RES_TXT=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t TXT -c test_gns_lookup.conf`
27gnunet-namestore -z $MY_EGO -d -n $LABEL -t TXT -V "$TEST_TXT" -e never -c test_gns_lookup.conf
28gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
29gnunet-arm -e -c test_gns_lookup.conf
30rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
31
32if [ "$RES_TXT" = "$TEST_TXT" ]
33then
34 exit 0
35else
36 echo "Failed to resolve to proper TXT, got '$RES_TXT'."
37 exit 1
38fi
diff --git a/src/cli/gns/test_gns_zkey_lookup.sh b/src/cli/gns/test_gns_zkey_lookup.sh
new file mode 100755
index 000000000..3d4aefc7c
--- /dev/null
+++ b/src/cli/gns/test_gns_zkey_lookup.sh
@@ -0,0 +1,39 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19
20TEST_IP="127.0.0.1"
21gnunet-arm -s -c test_gns_lookup.conf
22gnunet-identity -C delegatedego -c test_gns_lookup.conf
23DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep delegatedego | awk '{print $3}')
24gnunet-identity -C testego -c test_gns_lookup.conf
25gnunet-namestore -p -z testego -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
26gnunet-namestore -p -z delegatedego -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
27RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.${DELEGATED_PKEY} -t A -c test_gns_lookup.conf`
28gnunet-namestore -z testego -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
29gnunet-namestore -z delegatedego -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
30gnunet-arm -e -c test_gns_lookup.conf
31rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
32
33if [ "$RES_IP" = "$TEST_IP" ]
34then
35 exit 0
36else
37 echo "Failed to resolve to proper IP, got $RES_IP, wanted $TEST_IP."
38 exit 1
39fi
diff --git a/src/cli/gns/test_gnunet_gns.sh.in b/src/cli/gns/test_gnunet_gns.sh.in
new file mode 100755
index 000000000..d0c07b4e4
--- /dev/null
+++ b/src/cli/gns/test_gnunet_gns.sh.in
@@ -0,0 +1,47 @@
1#!/bin/bash
2# This file is in the public domain.
3# test -z being correct was a false assumption here.
4# I have no executable 'fooble', but this will
5# return 1:
6# if test -z "`which fooble`"; then echo 1; fi
7# The command builtin might not work with busybox's ash
8# but this works for now.
9dir=$(dirname "$0")
10
11existence() {
12 command -v "$1" >/dev/null 2>&1
13}
14
15LOCATION=`existence gnunet-config`
16if test -z $LOCATION; then
17 LOCATION="gnunet-config"
18fi
19$LOCATION --version
20if test $? != 0
21then
22 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
23 exit 77
24fi
25
26trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT
27ME=`whoami`
28if [ "$ME" != "root" ]
29then
30 echo "This test only works if run as root. Skipping."
31 exit 77
32fi
33export PATH=".:$PATH"
34gnunet-service-gns -c gns.conf &
35sleep 1
36LO=`nslookup alice.gnu | grep Address | tail -n1`
37if [ "$LO" != "Address: 1.2.3.4" ]
38then
39 echo "Fail: $LO"
40fi
41LO=`nslookup www.bob.gnu | grep Address | tail -n1`
42if [ "$LO" != "Address: 4.5.6.7" ]
43then
44 echo "Fail: $LO"
45fi
46# XXX: jobs. a builtin by bash, netbsd sh, maybe leave it be for now.
47kill `jobs -p`
diff --git a/src/cli/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey b/src/cli/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey
new file mode 100644
index 000000000..895946037
--- /dev/null
+++ b/src/cli/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey
Binary files differ
diff --git a/src/cli/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey b/src/cli/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey
new file mode 100644
index 000000000..3ef49f0ac
--- /dev/null
+++ b/src/cli/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey
Binary files differ
diff --git a/src/cli/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey b/src/cli/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey
new file mode 100644
index 000000000..89e0b3a0a
--- /dev/null
+++ b/src/cli/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey
Binary files differ
diff --git a/src/cli/gns/zonefiles/test_zonekey b/src/cli/gns/zonefiles/test_zonekey
new file mode 100644
index 000000000..870c56315
--- /dev/null
+++ b/src/cli/gns/zonefiles/test_zonekey
Binary files differ
diff --git a/src/cli/identity/.gitignore b/src/cli/identity/.gitignore
new file mode 100644
index 000000000..1c5862dbb
--- /dev/null
+++ b/src/cli/identity/.gitignore
@@ -0,0 +1 @@
gnunet-identity
diff --git a/src/cli/identity/Makefile.am b/src/cli/identity/Makefile.am
new file mode 100644
index 000000000..68bcc7a41
--- /dev/null
+++ b/src/cli/identity/Makefile.am
@@ -0,0 +1,35 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11pkgcfgdir= $(pkgdatadir)/config.d/
12
13bin_PROGRAMS = \
14 gnunet-identity
15
16gnunet_identity_SOURCES = \
17 gnunet-identity.c
18gnunet_identity_LDADD = \
19 $(top_builddir)/src/service/identity/libgnunetidentity.la \
20 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
21 $(top_builddir)/src/lib/util/libgnunetutil.la \
22 $(GN_LIBINTL)
23
24check_SCRIPTS = \
25 test_identity_messages.sh
26
27# if ENABLE_TEST_RUN
28# AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
29# TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
30# endif
31
32
33EXTRA_DIST = \
34 test_identity_messages.sh
35
diff --git a/src/cli/identity/gnunet-identity.c b/src/cli/identity/gnunet-identity.c
new file mode 100644
index 000000000..9fe4ccc51
--- /dev/null
+++ b/src/cli/identity/gnunet-identity.c
@@ -0,0 +1,624 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2018, 2019 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 identity/gnunet-identity.c
22 * @brief IDENTITY management command line tool
23 * @author Christian Grothoff
24 *
25 * Todo:
26 * - add options to get default egos
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31
32
33/**
34 * Return value from main on timeout.
35 */
36#define TIMEOUT_STATUS_CODE 40
37
38/**
39 * Handle to IDENTITY service.
40 */
41static struct GNUNET_IDENTITY_Handle *sh;
42
43/**
44 * Was "list" specified?
45 */
46static int list;
47
48/**
49 * Was "monitor" specified?
50 */
51static int monitor;
52
53/**
54 * Was "private" specified?
55 */
56static int private_keys;
57
58/**
59 * Was "verbose" specified?
60 */
61static unsigned int verbose;
62
63/**
64 * Was "quiet" specified?
65 */
66static int quiet;
67
68/**
69 * Was "eddsa" specified?
70 */
71static int type_eddsa;
72
73/**
74 * -W option
75 */
76static char *write_msg;
77
78/**
79 * -R option
80 */
81static char *read_msg;
82
83/**
84 * -C option
85 */
86static char *create_ego;
87
88/**
89 * -D option
90 */
91static char *delete_ego;
92
93/**
94 * -P option
95 */
96static char *privkey_ego;
97
98/**
99 * -k option
100 */
101static char *pubkey_msg;
102
103/**
104 * -s option.
105 */
106static char *set_ego;
107
108/**
109 * Operation handle for set operation.
110 */
111static struct GNUNET_IDENTITY_Operation *set_op;
112
113/**
114 * Handle for create operation.
115 */
116static struct GNUNET_IDENTITY_Operation *create_op;
117
118/**
119 * Handle for delete operation.
120 */
121static struct GNUNET_IDENTITY_Operation *delete_op;
122
123/**
124 * Private key from command line option, or NULL.
125 */
126struct GNUNET_CRYPTO_PrivateKey pk;
127
128/**
129 * Value to return from #main().
130 */
131static int global_ret;
132
133
134/**
135 * Task run on shutdown.
136 *
137 * @param cls NULL
138 */
139static void
140shutdown_task (void *cls)
141{
142 if (NULL != set_op)
143 {
144 GNUNET_IDENTITY_cancel (set_op);
145 set_op = NULL;
146 }
147 if (NULL != create_op)
148 {
149 GNUNET_IDENTITY_cancel (create_op);
150 create_op = NULL;
151 }
152 if (NULL != delete_op)
153 {
154 GNUNET_IDENTITY_cancel (delete_op);
155 delete_op = NULL;
156 }
157 if (NULL != set_ego)
158 {
159 GNUNET_free (set_ego);
160 set_ego = NULL;
161 }
162 GNUNET_IDENTITY_disconnect (sh);
163 sh = NULL;
164}
165
166
167/**
168 * Test if we are finished yet.
169 */
170static void
171test_finished (void)
172{
173 if ( (NULL == create_op) &&
174 (NULL == delete_op) &&
175 (NULL == set_op) &&
176 (NULL == write_msg) &&
177 (NULL == read_msg) &&
178 (! list) &&
179 (! monitor))
180 {
181 if (TIMEOUT_STATUS_CODE == global_ret)
182 global_ret = 0;
183 GNUNET_SCHEDULER_shutdown ();
184 }
185}
186
187
188/**
189 * Deletion operation finished.
190 *
191 * @param cls pointer to operation handle
192 * @param ec the error code
193 */
194static void
195delete_finished (void *cls,
196 enum GNUNET_ErrorCode ec)
197{
198 struct GNUNET_IDENTITY_Operation **op = cls;
199
200 *op = NULL;
201 if (GNUNET_EC_NONE != ec)
202 fprintf (stderr, "%s\n", GNUNET_ErrorCode_get_hint (ec));
203 test_finished ();
204}
205
206
207/**
208 * Creation operation finished.
209 *
210 * @param cls pointer to operation handle
211 * @param pk private key of the ego, or NULL on error
212 * @param ec the error code
213 */
214static void
215create_finished (void *cls,
216 const struct GNUNET_CRYPTO_PrivateKey *pk,
217 enum GNUNET_ErrorCode ec)
218{
219 struct GNUNET_IDENTITY_Operation **op = cls;
220
221 *op = NULL;
222 if (NULL == pk)
223 {
224 fprintf (stderr,
225 _ ("Failed to create ego: %s\n"),
226 GNUNET_ErrorCode_get_hint (ec));
227 global_ret = 1;
228 }
229 else if (verbose)
230 {
231 struct GNUNET_CRYPTO_PublicKey pub;
232 char *pubs;
233
234 GNUNET_CRYPTO_key_get_public (pk, &pub);
235 pubs = GNUNET_CRYPTO_public_key_to_string (&pub);
236 if (private_keys)
237 {
238 char *privs;
239
240 privs = GNUNET_CRYPTO_private_key_to_string (pk);
241 fprintf (stdout, "%s - %s\n", pubs, privs);
242 GNUNET_free (privs);
243 }
244 else
245 {
246 fprintf (stdout, "%s\n", pubs);
247 }
248 GNUNET_free (pubs);
249 }
250 test_finished ();
251}
252
253
254/**
255 * Encrypt a message given with -W, encrypted using public key of
256 * an identity given with -k.
257 */
258static void
259write_encrypted_message (void)
260{
261 struct GNUNET_CRYPTO_PublicKey recipient;
262 size_t ct_len = strlen (write_msg) + 1
263 + GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES;
264 unsigned char ct[ct_len];
265 if (GNUNET_CRYPTO_public_key_from_string (pubkey_msg, &recipient) !=
266 GNUNET_SYSERR)
267 {
268 size_t msg_len = strlen (write_msg) + 1;
269 if (GNUNET_OK == GNUNET_CRYPTO_encrypt (write_msg,
270 msg_len,
271 &recipient,
272 ct, ct_len))
273 {
274 char *serialized_msg;
275 serialized_msg = GNUNET_STRINGS_data_to_string_alloc (ct, ct_len);
276 fprintf (stdout,
277 "%s\n",
278 serialized_msg);
279 GNUNET_free (serialized_msg);
280 }
281 else
282 {
283 fprintf (stderr, "Error during encryption.\n");
284 global_ret = 1;
285 }
286 }
287 else
288 {
289 fprintf (stderr, "Invalid recipient public key.\n");
290 global_ret = 1;
291 }
292}
293
294
295/**
296 * Decrypt a message given with -R, encrypted using public key of @c ego
297 * and ephemeral key given with -k.
298 *
299 * @param ego ego whose private key is used for decryption
300 */
301static void
302read_encrypted_message (struct GNUNET_IDENTITY_Ego *ego)
303{
304 char *deserialized_msg;
305 size_t msg_len;
306 if (GNUNET_OK == GNUNET_STRINGS_string_to_data_alloc (read_msg, strlen (
307 read_msg),
308 (void **) &
309 deserialized_msg,
310 &msg_len))
311 {
312 if (GNUNET_OK == GNUNET_CRYPTO_decrypt (deserialized_msg,
313 msg_len,
314 GNUNET_IDENTITY_ego_get_private_key (
315 ego),
316 deserialized_msg, msg_len))
317 {
318 deserialized_msg[msg_len - 1] = '\0';
319 fprintf (stdout,
320 "%s\n",
321 deserialized_msg);
322 }
323 else
324 {
325 fprintf (stderr, "Failed to decrypt message.\n");
326 global_ret = 1;
327 }
328 GNUNET_free (deserialized_msg);
329 }
330 else
331 {
332 fprintf (stderr, "Invalid message format.\n");
333 global_ret = 1;
334 }
335}
336
337
338/**
339 * If listing is enabled, prints information about the egos.
340 *
341 * This function is initially called for all egos and then again
342 * whenever a ego's identifier changes or if it is deleted. At the
343 * end of the initial pass over all egos, the function is once called
344 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
345 * be invoked in the future or that there was an error.
346 *
347 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this
348 * function is only called ONCE, and 'NULL' being passed in 'ego' does
349 * indicate an error (for example because name is taken or no default value is
350 * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the
351 * value WILL be passed to a subsequent call to the identity callback of
352 * 'GNUNET_IDENTITY_connect' (if that one was not NULL).
353 *
354 * When an identity is renamed, this function is called with the
355 * (known) ego but the NEW identifier.
356 *
357 * When an identity is deleted, this function is called with the
358 * (known) ego and "NULL" for the 'identifier'. In this case,
359 * the 'ego' is henceforth invalid (and the 'ctx' should also be
360 * cleaned up).
361 *
362 * @param cls closure
363 * @param ego ego handle
364 * @param ctx context for application to store data for this ego
365 * (during the lifetime of this process, initially NULL)
366 * @param identifier identifier assigned by the user for this ego,
367 * NULL if the user just deleted the ego and it
368 * must thus no longer be used
369 */
370static void
371print_ego (void *cls,
372 struct GNUNET_IDENTITY_Ego *ego,
373 void **ctx,
374 const char *identifier)
375{
376 struct GNUNET_CRYPTO_PublicKey pk;
377 char *s;
378 char *privs;
379
380 if ( (NULL == ego) &&
381 (NULL != set_ego) &&
382 (NULL != read_msg) )
383 {
384 fprintf (stderr,
385 "Ego `%s' is not known, cannot decrypt message.\n",
386 set_ego);
387 GNUNET_free (read_msg);
388 read_msg = NULL;
389 GNUNET_free (set_ego);
390 set_ego = NULL;
391 }
392 if ((NULL == ego) && (! monitor))
393 {
394 list = 0;
395 test_finished ();
396 return;
397 }
398 if (! (list | monitor) && (NULL == read_msg))
399 return;
400 if ( (NULL == ego) ||
401 (NULL == identifier) )
402 return;
403 if ( (NULL != set_ego) &&
404 (0 != strcmp (identifier,
405 set_ego)) )
406 return;
407 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
408 s = GNUNET_CRYPTO_public_key_to_string (&pk);
409 privs = GNUNET_CRYPTO_private_key_to_string (
410 GNUNET_IDENTITY_ego_get_private_key (ego));
411 if ((NULL != read_msg) && (NULL != set_ego))
412 {
413 // due to the check above, set_ego and the identifier are equal
414 read_encrypted_message (ego);
415 GNUNET_free (read_msg);
416 read_msg = NULL;
417 }
418 else if ((monitor) || (NULL != identifier))
419 {
420 if (quiet)
421 {
422 if (private_keys)
423 fprintf (stdout, "%s - %s\n", s, privs);
424 else
425 fprintf (stdout, "%s\n", s);
426 }
427 else
428 {
429 if (private_keys)
430 fprintf (stdout, "%s - %s - %s - %s\n",
431 identifier, s, privs,
432 (ntohl (pk.type) == GNUNET_PUBLIC_KEY_TYPE_ECDSA) ?
433 "ECDSA" : "EdDSA");
434 else
435 fprintf (stdout, "%s - %s - %s\n",
436 identifier, s,
437 (ntohl (pk.type) == GNUNET_PUBLIC_KEY_TYPE_ECDSA) ?
438 "ECDSA" : "EdDSA");
439
440 }
441 }
442 GNUNET_free (privs);
443 GNUNET_free (s);
444}
445
446
447/**
448 * Main function that will be run by the scheduler.
449 *
450 * @param cls closure
451 * @param args remaining command-line arguments
452 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
453 * @param cfg configuration
454 */
455static void
456run (void *cls,
457 char *const *args,
458 const char *cfgfile,
459 const struct GNUNET_CONFIGURATION_Handle *cfg)
460{
461 if ((NULL != read_msg) && (NULL == set_ego))
462 {
463 fprintf (stderr,
464 "Option -R requires options -e to be specified as well.\n");
465 return;
466 }
467
468 if ((NULL != write_msg) && (NULL == pubkey_msg))
469 {
470 fprintf (stderr, "Option -W requires option -k to be specified as well.\n");
471 return;
472 }
473 sh = GNUNET_IDENTITY_connect (cfg,
474 (monitor | list) ||
475 (NULL != set_ego)
476 ? &print_ego
477 : NULL,
478 NULL);
479 if (NULL != write_msg)
480 {
481 write_encrypted_message ();
482 GNUNET_free (write_msg);
483 write_msg = NULL;
484 }
485 // read message is handled in ego callback (print_ego)
486 if (NULL != delete_ego)
487 delete_op =
488 GNUNET_IDENTITY_delete (sh,
489 delete_ego,
490 &delete_finished,
491 &delete_op);
492 if (NULL != create_ego)
493 {
494 if (NULL != privkey_ego)
495 {
496 GNUNET_STRINGS_string_to_data (privkey_ego,
497 strlen (privkey_ego),
498 &pk,
499 sizeof(struct
500 GNUNET_CRYPTO_PrivateKey));
501 create_op =
502 GNUNET_IDENTITY_create (sh,
503 create_ego,
504 &pk,
505 0, // Ignored
506 &create_finished,
507 &create_op);
508 }
509 else
510 create_op =
511 GNUNET_IDENTITY_create (sh,
512 create_ego,
513 NULL,
514 (type_eddsa) ?
515 GNUNET_PUBLIC_KEY_TYPE_EDDSA :
516 GNUNET_PUBLIC_KEY_TYPE_ECDSA,
517 &create_finished,
518 &create_op);
519 }
520 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
521 NULL);
522 test_finished ();
523}
524
525
526/**
527 * The main function.
528 *
529 * @param argc number of arguments from the command line
530 * @param argv command line arguments
531 * @return 0 ok, 1 on error
532 */
533int
534main (int argc, char *const *argv)
535{
536 struct GNUNET_GETOPT_CommandLineOption options[] = {
537 GNUNET_GETOPT_option_string ('C',
538 "create",
539 "NAME",
540 gettext_noop ("create ego NAME"),
541 &create_ego),
542 GNUNET_GETOPT_option_string ('D',
543 "delete",
544 "NAME",
545 gettext_noop ("delete ego NAME "),
546 &delete_ego),
547 GNUNET_GETOPT_option_string ('P',
548 "privkey",
549 "PRIVATE_KEY",
550 gettext_noop (
551 "set the private key for the identity to PRIVATE_KEY (use together with -C)"),
552 &privkey_ego),
553 GNUNET_GETOPT_option_string ('R',
554 "read",
555 "MESSAGE",
556 gettext_noop (
557 "Read and decrypt message encrypted for the given ego (use together with -e EGO)"),
558 &read_msg),
559 GNUNET_GETOPT_option_string ('W',
560 "write",
561 "MESSAGE",
562 gettext_noop (
563 "Encrypt and write message for recipient identity PULBIC_KEY, (use together with -k RECIPIENT_PUBLIC_KEY)"),
564 &write_msg),
565 GNUNET_GETOPT_option_flag ('X',
566 "eddsa",
567 gettext_noop (
568 "generate an EdDSA identity. (use together with -C) EXPERIMENTAL"),
569 &type_eddsa),
570 GNUNET_GETOPT_option_flag ('d',
571 "display",
572 gettext_noop ("display all egos"),
573 &list),
574 GNUNET_GETOPT_option_flag ('q',
575 "quiet",
576 gettext_noop ("reduce output"),
577 &quiet),
578 GNUNET_GETOPT_option_string (
579 'e',
580 "ego",
581 "NAME",
582 gettext_noop (
583 "restrict results to NAME (use together with -d) or read and decrypt a message for NAME (use together with -R)"),
584 &set_ego),
585 GNUNET_GETOPT_option_string ('k',
586 "key",
587 "PUBLIC_KEY",
588 gettext_noop (
589 "The public key of the recipient (with -W)"),
590 &pubkey_msg),
591 GNUNET_GETOPT_option_flag ('m',
592 "monitor",
593 gettext_noop ("run in monitor mode egos"),
594 &monitor),
595 GNUNET_GETOPT_option_flag ('p',
596 "private-keys",
597 gettext_noop ("display private keys as well"),
598 &private_keys),
599 GNUNET_GETOPT_option_verbose (&verbose),
600 GNUNET_GETOPT_OPTION_END
601 };
602 int res;
603
604 if (GNUNET_OK !=
605 GNUNET_STRINGS_get_utf8_args (argc, argv,
606 &argc, &argv))
607 return 4;
608 global_ret = TIMEOUT_STATUS_CODE; /* timeout */
609 res = GNUNET_PROGRAM_run (argc,
610 argv,
611 "gnunet-identity",
612 gettext_noop ("Maintain egos"),
613 options,
614 &run,
615 NULL);
616 GNUNET_free_nz ((void *) argv);
617
618 if (GNUNET_OK != res)
619 return 3;
620 return global_ret;
621}
622
623
624/* end of gnunet-identity.c */
diff --git a/src/cli/identity/meson.build b/src/cli/identity/meson.build
new file mode 100644
index 000000000..958a4ccd5
--- /dev/null
+++ b/src/cli/identity/meson.build
@@ -0,0 +1,9 @@
1executable ('gnunet-identity',
2 ['gnunet-identity.c'],
3 dependencies: [libgnunetidentity_dep,
4 libgnunetutil_dep,
5 libgnunetstatistics_dep],
6 include_directories: [incdir, configuration_inc],
7 install: true,
8 install_dir: get_option('bindir'))
9
diff --git a/src/cli/identity/test_identity_messages.sh b/src/cli/identity/test_identity_messages.sh
new file mode 100755
index 000000000..edb4d5805
--- /dev/null
+++ b/src/cli/identity/test_identity_messages.sh
@@ -0,0 +1,50 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_identity.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_identity.conf -s PATHS -o GNUNET_HOME -f`
17
18which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19
20TEST_MSG="This is a test message. 123"
21gnunet-arm -s -c test_identity.conf
22gnunet-identity -C recipientego -c test_identity.conf
23gnunet-identity -C recipientegoed -X -c test_identity.conf
24RECIPIENT_KEY=`gnunet-identity -d -e recipientego -q -c test_identity.conf`
25MSG_ENC=`gnunet-identity -W "$TEST_MSG" -k $RECIPIENT_KEY -c test_identity.conf`
26if [ $? == 0 ]
27then
28 MSG_DEC=`gnunet-identity -R "$MSG_ENC" -e recipientego -c test_identity.conf`
29fi
30RECIPIENT_KEY_ED=`gnunet-identity -d -e recipientegoed -q -c test_identity.conf`
31MSG_ENC_ED=`gnunet-identity -W "$TEST_MSG" -k $RECIPIENT_KEY_ED -c test_identity.conf`
32if [ $? == 0 ]
33then
34 MSG_DEC_ED=`gnunet-identity -R "$MSG_ENC_ED" -e recipientegoed -c test_identity.conf`
35fi
36gnunet-identity -D recipientego -c test_identity.conf
37gnunet-identity -D recipientegoed -c test_identity.conf
38gnunet-arm -e -c test_identity.conf
39if [ "$TEST_MSG" != "$MSG_DEC" ]
40then
41 diff <(echo "$TEST_MSG" ) <(echo "$MSG_DEC")
42 echo "Failed - \"$TEST_MSG\" != \"$MSG_DEC\""
43 exit 1
44fi
45if [ "$TEST_MSG" != "$MSG_DEC_ED" ]
46then
47 diff <(echo "$TEST_MSG" ) <(echo "$MSG_DEC_ED")
48 echo "Failed - \"$TEST_MSG\" != \"$MSG_DEC_ED\""
49 exit 1
50fi
diff --git a/src/cli/meson.build b/src/cli/meson.build
new file mode 100644
index 000000000..12662933d
--- /dev/null
+++ b/src/cli/meson.build
@@ -0,0 +1,20 @@
1subdir('util')
2subdir('arm')
3subdir('statistics')
4subdir('peerstore')
5subdir('datastore')
6subdir('nat')
7subdir('nat-auto')
8subdir('core')
9subdir('nse')
10subdir('dht')
11subdir('identity')
12subdir('namecache')
13subdir('namestore')
14subdir('cadet')
15subdir('revocation')
16subdir('vpn')
17subdir('gns')
18subdir('fs')
19subdir('reclaim')
20subdir('messenger')
diff --git a/src/cli/messenger/.gitignore b/src/cli/messenger/.gitignore
new file mode 100644
index 000000000..1c1447be8
--- /dev/null
+++ b/src/cli/messenger/.gitignore
@@ -0,0 +1 @@
gnunet-messenger
diff --git a/src/cli/messenger/Makefile.am b/src/cli/messenger/Makefile.am
new file mode 100644
index 000000000..741e2b7b9
--- /dev/null
+++ b/src/cli/messenger/Makefile.am
@@ -0,0 +1,25 @@
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
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13AM_CLFAGS = -g
14
15bin_PROGRAMS = \
16 gnunet-messenger
17
18gnunet_messenger_SOURCES = \
19 gnunet-messenger.c
20gnunet_messenger_LDADD = \
21 $(top_builddir)/src/service/messenger/libgnunetmessenger.la \
22 $(top_builddir)/src/service/identity/libgnunetidentity.la \
23 $(top_builddir)/src/lib/util/libgnunetutil.la
24gnunet_messenger_LDFLAGS = \
25 $(GN_LIBINTL)
diff --git a/src/cli/messenger/gnunet-messenger.c b/src/cli/messenger/gnunet-messenger.c
new file mode 100644
index 000000000..6bff0b25d
--- /dev/null
+++ b/src/cli/messenger/gnunet-messenger.c
@@ -0,0 +1,415 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 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 * @author Tobias Frisch
22 * @file src/messenger/gnunet-messenger.c
23 * @brief Print information about messenger groups.
24 */
25
26#include <stdio.h>
27#include <unistd.h>
28
29#include "gnunet_identity_service.h"
30#include "gnunet_messenger_service.h"
31#include "gnunet_util_lib.h"
32
33const struct GNUNET_CONFIGURATION_Handle *config;
34struct GNUNET_MESSENGER_Handle *messenger;
35
36/**
37 * Function called whenever a message is received or sent.
38 *
39 * @param[in,out] cls Closure
40 * @param[in] room Room
41 * @param[in] sender Sender of message
42 * @param[in] message Message
43 * @param[in] hash Hash of message
44 * @param[in] flags Flags of message
45 */
46void
47on_message (void *cls,
48 struct GNUNET_MESSENGER_Room *room,
49 const struct GNUNET_MESSENGER_Contact *sender,
50 const struct GNUNET_MESSENGER_Contact *recipient,
51 const struct GNUNET_MESSENGER_Message *message,
52 const struct GNUNET_HashCode *hash,
53 enum GNUNET_MESSENGER_MessageFlags flags)
54{
55 const char *sender_name = GNUNET_MESSENGER_contact_get_name (sender);
56 const char *recipient_name = GNUNET_MESSENGER_contact_get_name (recipient);
57
58 if (! sender_name)
59 sender_name = "anonymous";
60
61 if (! recipient_name)
62 recipient_name = "anonymous";
63
64 printf ("[%s ->", GNUNET_h2s (&(message->header.previous)));
65 printf (" %s]", GNUNET_h2s (hash));
66 printf ("[%s] ", GNUNET_sh2s (&(message->header.sender_id)));
67
68 if (flags & GNUNET_MESSENGER_FLAG_PRIVATE)
69 printf ("*( '%s' ) ", recipient_name);
70
71 switch (message->header.kind)
72 {
73 case GNUNET_MESSENGER_KIND_JOIN:
74 {
75 printf ("* '%s' joined the room!\n", sender_name);
76 break;
77 }
78 case GNUNET_MESSENGER_KIND_NAME:
79 {
80 printf ("* '%s' gets renamed to '%s'\n", sender_name,
81 message->body.name.name);
82 break;
83 }
84 case GNUNET_MESSENGER_KIND_LEAVE:
85 {
86 printf ("* '%s' leaves the room!\n", sender_name);
87 break;
88 }
89 case GNUNET_MESSENGER_KIND_PEER:
90 {
91 printf ("* '%s' opened the room on: %s\n", sender_name,
92 GNUNET_i2s_full (&(message->body.peer.peer)));
93 break;
94 }
95 case GNUNET_MESSENGER_KIND_TEXT:
96 {
97 if (flags & GNUNET_MESSENGER_FLAG_SENT)
98 printf (">");
99 else
100 printf ("<");
101
102 printf (" '%s' says: \"%s\"\n", sender_name, message->body.text.text);
103 break;
104 }
105 default:
106 {
107 printf ("~ message: %s\n",
108 GNUNET_MESSENGER_name_of_kind (message->header.kind));
109 break;
110 }
111 }
112
113 if ((GNUNET_MESSENGER_KIND_JOIN == message->header.kind) &&
114 (flags & GNUNET_MESSENGER_FLAG_SENT))
115 {
116 const char *name = GNUNET_MESSENGER_get_name (messenger);
117
118 if (! name)
119 return;
120
121 struct GNUNET_MESSENGER_Message response;
122 response.header.kind = GNUNET_MESSENGER_KIND_NAME;
123 response.body.name.name = GNUNET_strdup (name);
124
125 GNUNET_MESSENGER_send_message (room, &response, NULL);
126
127 GNUNET_free (response.body.name.name);
128 }
129}
130
131
132struct GNUNET_SCHEDULER_Task *read_task;
133struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
134
135/**
136 * Task to shut down this application.
137 *
138 * @param[in,out] cls Closure
139 */
140static void
141shutdown_hook (void *cls)
142{
143 struct GNUNET_MESSENGER_Room *room = cls;
144
145 if (read_task)
146 GNUNET_SCHEDULER_cancel (read_task);
147
148 if (room)
149 GNUNET_MESSENGER_close_room (room);
150
151 if (messenger)
152 GNUNET_MESSENGER_disconnect (messenger);
153
154 if (ego_lookup)
155 GNUNET_IDENTITY_ego_lookup_cancel (ego_lookup);
156}
157
158
159static void
160listen_stdio (void *cls);
161
162#define MAX_BUFFER_SIZE 60000
163
164static int
165iterate_send_private_message (void *cls,
166 struct GNUNET_MESSENGER_Room *room,
167 const struct GNUNET_MESSENGER_Contact *contact)
168{
169 struct GNUNET_MESSENGER_Message *message = cls;
170
171 if (GNUNET_MESSENGER_contact_get_key (contact))
172 GNUNET_MESSENGER_send_message (room, message, contact);
173
174 return GNUNET_YES;
175}
176
177
178int private_mode;
179
180/**
181 * Task run in stdio mode, after some data is available at stdin.
182 *
183 * @param[in,out] cls Closure
184 */
185static void
186read_stdio (void *cls)
187{
188 read_task = NULL;
189
190 char buffer[MAX_BUFFER_SIZE];
191 ssize_t length;
192
193 length = read (0, buffer, MAX_BUFFER_SIZE);
194
195 if ((length <= 0) || (length >= MAX_BUFFER_SIZE))
196 {
197 GNUNET_SCHEDULER_shutdown ();
198 return;
199 }
200
201 if (buffer[length - 1] == '\n')
202 buffer[length - 1] = '\0';
203 else
204 buffer[length] = '\0';
205
206 struct GNUNET_MESSENGER_Room *room = cls;
207
208 struct GNUNET_MESSENGER_Message message;
209 message.header.kind = GNUNET_MESSENGER_KIND_TEXT;
210 message.body.text.text = buffer;
211
212 if (GNUNET_YES == private_mode)
213 GNUNET_MESSENGER_iterate_members (room, iterate_send_private_message,
214 &message);
215 else
216 GNUNET_MESSENGER_send_message (room, &message, NULL);
217
218 read_task = GNUNET_SCHEDULER_add_now (listen_stdio, cls);
219}
220
221
222/**
223 * Wait for input on STDIO and send it out over the #ch.
224 *
225 * @param[in,out] cls Closure
226 */
227static void
228listen_stdio (void *cls)
229{
230 read_task = NULL;
231
232 struct GNUNET_NETWORK_FDSet *rs = GNUNET_NETWORK_fdset_create ();
233
234 GNUNET_NETWORK_fdset_set_native (rs, 0);
235
236 read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
237 GNUNET_TIME_UNIT_FOREVER_REL, rs,
238 NULL, &read_stdio, cls);
239
240 GNUNET_NETWORK_fdset_destroy (rs);
241}
242
243
244/**
245 * Initial task to startup application.
246 *
247 * @param[in,out] cls Closure
248 */
249static void
250idle (void *cls)
251{
252 struct GNUNET_MESSENGER_Room *room = cls;
253
254 printf ("* You joined the room.\n");
255
256 read_task = GNUNET_SCHEDULER_add_now (listen_stdio, room);
257}
258
259
260char *door_id;
261char *ego_name;
262char *room_key;
263
264struct GNUNET_SCHEDULER_Task *shutdown_task;
265
266/**
267 * Function called when an identity is retrieved.
268 *
269 * @param[in,out] cls Closure
270 * @param[in,out] handle Handle of messenger service
271 */
272static void
273on_identity (void *cls,
274 struct GNUNET_MESSENGER_Handle *handle)
275{
276 struct GNUNET_HashCode key;
277 memset (&key, 0, sizeof(key));
278
279 if (room_key)
280 GNUNET_CRYPTO_hash (room_key, strlen (room_key), &key);
281
282 struct GNUNET_PeerIdentity door_peer;
283 struct GNUNET_PeerIdentity *door = NULL;
284
285 if ((door_id) &&
286 (GNUNET_OK == GNUNET_CRYPTO_eddsa_public_key_from_string (door_id,
287 strlen (
288 door_id),
289 &(door_peer.
290 public_key))))
291 door = &door_peer;
292
293 const char *name = GNUNET_MESSENGER_get_name (handle);
294
295 if (! name)
296 name = "anonymous";
297
298 printf ("* Welcome to the messenger, '%s'!\n", name);
299
300 struct GNUNET_MESSENGER_Room *room;
301
302 if (door)
303 {
304 printf ("* You try to entry a room...\n");
305
306 room = GNUNET_MESSENGER_enter_room (messenger, door, &key);
307 }
308 else
309 {
310 printf ("* You try to open a room...\n");
311
312 room = GNUNET_MESSENGER_open_room (messenger, &key);
313 }
314
315 GNUNET_SCHEDULER_cancel (shutdown_task);
316
317 shutdown_task = GNUNET_SCHEDULER_add_shutdown (shutdown_hook, room);
318
319 if (! room)
320 GNUNET_SCHEDULER_shutdown ();
321 else
322 {
323 GNUNET_SCHEDULER_add_delayed_with_priority (
324 GNUNET_TIME_relative_get_zero_ (),
325 GNUNET_SCHEDULER_PRIORITY_IDLE,
326 idle, room);
327 }
328}
329
330
331static void
332on_ego_lookup (void *cls,
333 struct GNUNET_IDENTITY_Ego *ego)
334{
335 ego_lookup = NULL;
336
337 const struct GNUNET_CRYPTO_PrivateKey *key;
338 key = ego ? GNUNET_IDENTITY_ego_get_private_key (ego) : NULL;
339
340 messenger = GNUNET_MESSENGER_connect (config, ego_name, key, &on_message,
341 NULL);
342
343 on_identity (NULL, messenger);
344}
345
346
347/**
348 * Main function that will be run by the scheduler.
349 *
350 * @param[in/out] cls closure
351 * @param[in] args remaining command-line arguments
352 * @param[in] cfgfile name of the configuration file used (for saving, can be NULL!)
353 * @param[in] cfg configuration
354 */
355static void
356run (void *cls,
357 char *const *args,
358 const char *cfgfile,
359 const struct GNUNET_CONFIGURATION_Handle *cfg)
360{
361 config = cfg;
362
363 if (ego_name)
364 {
365 ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &on_ego_lookup,
366 NULL);
367 messenger = NULL;
368 }
369 else
370 {
371 ego_lookup = NULL;
372 messenger = GNUNET_MESSENGER_connect (cfg, NULL, NULL, &on_message, NULL);
373 }
374
375 shutdown_task = GNUNET_SCHEDULER_add_shutdown (shutdown_hook, NULL);
376
377 if (messenger)
378 on_identity (NULL, messenger);
379}
380
381
382/**
383 * The main function to obtain messenger information.
384 *
385 * @param[in] argc number of arguments from the command line
386 * @param[in] argv command line arguments
387 * @return #EXIT_SUCCESS ok, #EXIT_FAILURE on error
388 */
389int
390main (int argc,
391 char **argv)
392{
393 const char *description =
394 "Open and connect to rooms using the MESSENGER to chat.";
395
396 struct GNUNET_GETOPT_CommandLineOption options[] = {
397 GNUNET_GETOPT_option_string ('d', "door", "PEERIDENTITY",
398 "peer identity to entry into the room",
399 &door_id),
400 GNUNET_GETOPT_option_string ('e', "ego", "IDENTITY",
401 "identity to use for messaging",
402 &ego_name),
403 GNUNET_GETOPT_option_string ('r', "room", "ROOMKEY",
404 "key of the room to connect to",
405 &room_key),
406 GNUNET_GETOPT_option_flag ('p', "private", "flag to enable private mode",
407 &private_mode),
408 GNUNET_GETOPT_OPTION_END
409 };
410
411 return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-messenger\0",
412 gettext_noop (description), options,
413 &run,
414 NULL) ? EXIT_SUCCESS : EXIT_FAILURE);
415}
diff --git a/src/cli/messenger/meson.build b/src/cli/messenger/meson.build
new file mode 100644
index 000000000..3a3870c9d
--- /dev/null
+++ b/src/cli/messenger/meson.build
@@ -0,0 +1,9 @@
1executable ('gnunet-messenger',
2 'gnunet-messenger.c',
3 dependencies: [libgnunetmessenger_dep,
4 libgnunetidentity_dep,
5 libgnunetutil_dep],
6 include_directories: [incdir, configuration_inc],
7 install: true,
8 install_dir: get_option('bindir'))
9
diff --git a/src/cli/namecache/.gitignore b/src/cli/namecache/.gitignore
new file mode 100644
index 000000000..54aa17e9f
--- /dev/null
+++ b/src/cli/namecache/.gitignore
@@ -0,0 +1 @@
gnunet-namecache
diff --git a/src/cli/namecache/Makefile.am b/src/cli/namecache/Makefile.am
new file mode 100644
index 000000000..48ee216be
--- /dev/null
+++ b/src/cli/namecache/Makefile.am
@@ -0,0 +1,20 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10bin_PROGRAMS = \
11 gnunet-namecache
12
13gnunet_namecache_SOURCES = \
14 gnunet-namecache.c
15gnunet_namecache_LDADD = \
16 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
17 $(top_builddir)/src/service/identity/libgnunetidentity.la \
18 $(top_builddir)/src/lib/util/libgnunetutil.la \
19 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
20 $(GN_LIBINTL)
diff --git a/src/cli/namecache/gnunet-namecache.c b/src/cli/namecache/gnunet-namecache.c
new file mode 100644
index 000000000..0236609aa
--- /dev/null
+++ b/src/cli/namecache/gnunet-namecache.c
@@ -0,0 +1,245 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 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 gnunet-namecache.c
22 * @brief command line tool to inspect the name cache
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - test
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_namecache_service.h"
33
34
35/**
36 * Handle to the namecache.
37 */
38static struct GNUNET_NAMECACHE_Handle *ns;
39
40/**
41 * Queue entry for the 'query' operation.
42 */
43static struct GNUNET_NAMECACHE_QueueEntry *qe;
44
45/**
46 * Name (label) of the records to list.
47 */
48static char *name;
49
50/**
51 * Public key of the zone to look in.
52 */
53static struct GNUNET_CRYPTO_PublicKey pubkey;
54
55/**
56 * Public key of the zone to look in, in ASCII.
57 */
58static char *pkey;
59
60/**
61 * Global return value
62 */
63static int ret;
64
65
66/**
67 * Task run on shutdown. Cleans up everything.
68 *
69 * @param cls unused
70 */
71static void
72do_shutdown (void *cls)
73{
74 if (NULL != qe)
75 {
76 GNUNET_NAMECACHE_cancel (qe);
77 qe = NULL;
78 }
79 if (NULL != ns)
80 {
81 GNUNET_NAMECACHE_disconnect (ns);
82 ns = NULL;
83 }
84}
85
86
87/**
88 * Process a record that was stored in the namecache in a block.
89 *
90 * @param cls closure, NULL
91 * @param rd_len number of entries in @a rd array
92 * @param rd array of records with data to store
93 */
94static void
95display_records_from_block (void *cls,
96 unsigned int rd_len,
97 const struct GNUNET_GNSRECORD_Data *rd)
98{
99 const char *typestring;
100 char *s;
101 unsigned int i;
102
103 if (0 == rd_len)
104 {
105 fprintf (stdout, _ ("No records found for `%s'"), name);
106 return;
107 }
108 fprintf (stdout, "%s:\n", name);
109 for (i = 0; i < rd_len; i++)
110 {
111 typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
112 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
113 rd[i].data,
114 rd[i].data_size);
115 if (NULL == s)
116 {
117 fprintf (stdout,
118 _ ("\tCorrupt or unsupported record of type %u\n"),
119 (unsigned int) rd[i].record_type);
120 continue;
121 }
122 fprintf (stdout, "\t%s: %s\n", typestring, s);
123 GNUNET_free (s);
124 }
125 fprintf (stdout, "%s", "\n");
126}
127
128
129/**
130 * Display block obtained from listing (by name).
131 *
132 * @param cls NULL
133 * @param block NULL if not found
134 */
135static void
136handle_block (void *cls, const struct GNUNET_GNSRECORD_Block *block)
137{
138 qe = NULL;
139 if (NULL == block)
140 {
141 fprintf (stderr, "No matching block found\n");
142 }
143 else if (GNUNET_OK !=
144 GNUNET_GNSRECORD_block_decrypt (block,
145 &pubkey,
146 name,
147 &display_records_from_block,
148 NULL))
149 {
150 fprintf (stderr, "Failed to decrypt block!\n");
151 }
152 GNUNET_SCHEDULER_shutdown ();
153}
154
155
156/**
157 * Main function that will be run.
158 *
159 * @param cls closure
160 * @param args remaining command-line arguments
161 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
162 * @param cfg configuration
163 */
164static void
165run (void *cls,
166 char *const *args,
167 const char *cfgfile,
168 const struct GNUNET_CONFIGURATION_Handle *cfg)
169{
170 struct GNUNET_HashCode dhash;
171
172 if (NULL == pkey)
173 {
174 fprintf (stderr, _ ("You must specify which zone should be accessed\n"));
175 return;
176 }
177
178 if (GNUNET_OK !=
179 GNUNET_CRYPTO_public_key_from_string (pkey, &pubkey))
180 {
181 fprintf (stderr, _ ("Invalid public key for zone `%s'\n"), pkey);
182 GNUNET_SCHEDULER_shutdown ();
183 return;
184 }
185 if (NULL == name)
186 {
187 fprintf (stderr, _ ("You must specify a name\n"));
188 return;
189 }
190
191 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
192 ns = GNUNET_NAMECACHE_connect (cfg);
193 GNUNET_GNSRECORD_query_from_public_key (&pubkey, name, &dhash);
194 qe = GNUNET_NAMECACHE_lookup_block (ns, &dhash, &handle_block, NULL);
195}
196
197
198/**
199 * The main function for gnunet-namecache.
200 *
201 * @param argc number of arguments from the command line
202 * @param argv command line arguments
203 * @return 0 ok, 1 on error
204 */
205int
206main (int argc, char *const *argv)
207{
208 struct GNUNET_GETOPT_CommandLineOption options[] =
209 { GNUNET_GETOPT_option_string ('n',
210 "name",
211 "NAME",
212 gettext_noop (
213 "name of the record to add/delete/display"),
214 &name),
215
216 GNUNET_GETOPT_option_string (
217 'z',
218 "zone",
219 "PKEY",
220 gettext_noop ("specifies the public key of the zone to look in"),
221 &pkey),
222
223 GNUNET_GETOPT_OPTION_END };
224
225 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
226 return 2;
227
228 GNUNET_log_setup ("gnunet-namecache", "WARNING", NULL);
229 if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
230 argv,
231 "gnunet-namecache",
232 _ ("GNUnet zone manipulation tool"),
233 options,
234 &run,
235 NULL))
236 {
237 GNUNET_free_nz ((void *) argv);
238 return 1;
239 }
240 GNUNET_free_nz ((void *) argv);
241 return ret;
242}
243
244
245/* end of gnunet-namecache.c */
diff --git a/src/cli/namecache/meson.build b/src/cli/namecache/meson.build
new file mode 100644
index 000000000..99ed68bca
--- /dev/null
+++ b/src/cli/namecache/meson.build
@@ -0,0 +1,10 @@
1executable ('gnunet-namecache',
2 gnunetnamecache_src,
3 dependencies: [libgnunetnamecache_dep,
4 libgnunetutil_dep,
5 libgnunetgnsrecord_dep,
6 libgnunetidentity_dep],
7 include_directories: [incdir, configuration_inc],
8 install: true,
9 install_dir: get_option('bindir'))
10
diff --git a/src/cli/namestore/.gitignore b/src/cli/namestore/.gitignore
new file mode 100644
index 000000000..3c0282e8c
--- /dev/null
+++ b/src/cli/namestore/.gitignore
@@ -0,0 +1,6 @@
1gnunet-namestore
2gnunet-namestore-dbtool
3gnunet-namestore-zonefile
4gnunet-namestore-fcfsd
5gnunet-zoneimport
6
diff --git a/src/cli/namestore/Makefile.am b/src/cli/namestore/Makefile.am
new file mode 100644
index 000000000..b666c8851
--- /dev/null
+++ b/src/cli/namestore/Makefile.am
@@ -0,0 +1,70 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10sqldir = $(prefix)/share/gnunet/sql/
11
12if USE_COVERAGE
13 AM_CFLAGS = --coverage -O0
14 XLIBS = -lgcov
15endif
16
17
18bin_PROGRAMS = \
19 gnunet-namestore \
20 gnunet-namestore-dbtool \
21 gnunet-namestore-zonefile \
22 gnunet-zoneimport
23
24gnunet_namestore_zonefile_SOURCES = \
25 gnunet-namestore-zonefile.c
26gnunet_namestore_zonefile_LDADD = \
27 $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
28 $(top_builddir)/src/service/identity/libgnunetidentity.la \
29 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
30 $(top_builddir)/src/lib/util/libgnunetutil.la \
31 $(GN_LIBINTL)
32
33gnunet_zoneimport_SOURCES = \
34 gnunet-zoneimport.c
35gnunet_zoneimport_LDADD = \
36 $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
37 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
38 $(top_builddir)/src/service/identity/libgnunetidentity.la \
39 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
40 $(top_builddir)/src/lib/util/libgnunetutil.la \
41 $(GN_LIBINTL)
42
43gnunet_namestore_SOURCES = \
44 gnunet-namestore.c
45gnunet_namestore_LDADD = \
46 $(top_builddir)/src/service/identity/libgnunetidentity.la \
47 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
48 $(top_builddir)/src/lib/util/libgnunetutil.la \
49 $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
50 $(GN_LIBINTL)
51
52gnunet_namestore_dbtool_SOURCES = \
53 gnunet-namestore-dbtool.c
54gnunet_namestore_dbtool_LDADD = \
55 $(top_builddir)/src/lib/util/libgnunetutil.la \
56 $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
57 $(GN_LIBINTL)
58
59
60
61check_SCRIPTS = \
62 test_namestore_put.sh \
63 test_namestore_put_stdin.sh \
64 test_namestore_lookup.sh \
65 test_namestore_delete.sh \
66 test_namestore_zonefile_import.sh
67
68EXTRA_DIST = \
69 example_zonefile \
70 $(check_SCRIPTS)
diff --git a/src/cli/namestore/example_zonefile b/src/cli/namestore/example_zonefile
new file mode 100644
index 000000000..5e380ff90
--- /dev/null
+++ b/src/cli/namestore/example_zonefile
@@ -0,0 +1,27 @@
1$ORIGIN example.com. ; designates the start of this zone file in the namespace
2$TTL 3600 ; default expiration time (in seconds) of all RRs without their own TTL value
3example.com. IN SOA ns.example.com. username.example.com. ( 2020091025 ; A comment
4 7200 ; Comment
5 ; empty line on purpose
6 3600
7 1209600
8 3600 )
9example.com. IN NS ns ; ns.example.com is a nameserver for example.com
10example.com. IN NS ns.somewhere.example. ; ns.somewhere.example is a backup nameserver for example.com
11example.com. IN MX 10 mail.example.com. ; mail.example.com is the mailserver for example.com
12@ IN MX 20 mail2.example.com. ; equivalent to above line, "@" represents zone origin
13@ IN MX 50 mail3 ; equivalent to above line, but using a relative host name
14b.example.com. IN A 192.0.2.1 ; IPv4 address for example.com
15 IN AAAA 2001:db8:10::1 ; IPv6 address for example.com
16ns IN A 192.0.2.2 ; IPv4 address for ns.example.com
17 IN AAAA 2001:db8:10::2 ; IPv6 address for ns.example.com
18www IN CNAME example.com. ; www.example.com is an alias for example.com
19wwwtest IN CNAME www ; wwwtest.example.com is another alias for www.example.com
20mail IN A 192.0.2.3 ; IPv4 address for mail.example.com
21mail2 IN A 192.0.2.4 ; IPv4 address for mail2.example.com
22mail3 IN A 192.0.2.5 ; IPv4 address for mail3.example.com
23
24mail3 IN TXT "This is ; quoted" ; A quoted comment separator
25$ORIGIN example.de.
26www2 IN A 192.0.2.7 ; IPv4 address for www2.example.de
27
diff --git a/src/cli/namestore/gnunet-namestore-dbtool.c b/src/cli/namestore/gnunet-namestore-dbtool.c
new file mode 100644
index 000000000..835d7a228
--- /dev/null
+++ b/src/cli/namestore/gnunet-namestore-dbtool.c
@@ -0,0 +1,199 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2019, 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 gnunet-namestore-dbtool.c
22 * @brief command line tool to manipulate the database backends for the namestore
23 * @author Martin Schanzenbach
24 *
25 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
28#include <gnunet_namestore_plugin.h>
29
30/**
31 * Name of the plugin argument
32 */
33static char *pluginname;
34
35/**
36 * Reset argument
37 */
38static int reset;
39
40/**
41 * Initialize argument
42 */
43static int init;
44
45/**
46 * Return code
47 */
48static int ret = 0;
49
50/**
51 * Task run on shutdown. Cleans up everything.
52 *
53 * @param cls unused
54 */
55static void
56do_shutdown (void *cls)
57{
58 (void) cls;
59 if (NULL != pluginname)
60 GNUNET_free (pluginname);
61}
62
63
64/**
65 * Main function that will be run.
66 *
67 * @param cls closure
68 * @param args remaining command-line arguments
69 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
70 * @param cfg configuration
71 */
72static void
73run (void *cls,
74 char *const *args,
75 const char *cfgfile,
76 const struct GNUNET_CONFIGURATION_Handle *cfg)
77{
78 char *db_lib_name;
79 struct GNUNET_NAMESTORE_PluginFunctions *plugin;
80
81 (void) cls;
82 (void) args;
83 (void) cfgfile;
84 if (NULL != args[0])
85 GNUNET_log (
86 GNUNET_ERROR_TYPE_WARNING,
87 _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
88 args[0]);
89
90 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
91 (void *) cfg);
92 if (NULL == pluginname)
93 {
94 fprintf (stderr, "No plugin given!\n");
95 ret = 1;
96 GNUNET_SCHEDULER_shutdown ();
97 return;
98 }
99 GNUNET_asprintf (&db_lib_name,
100 "libgnunet_plugin_namestore_%s",
101 pluginname);
102 plugin = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
103 if (NULL == plugin)
104 {
105 fprintf (stderr,
106 "Failed to load %s!\n",
107 db_lib_name);
108 ret = 1;
109 GNUNET_SCHEDULER_shutdown ();
110 GNUNET_free (db_lib_name);
111 return;
112 }
113 if (reset)
114 {
115 if (GNUNET_OK !=
116 plugin->drop_tables (plugin->cls))
117 {
118 fprintf (stderr,
119 "Failed to reset database\n");
120 ret = 1;
121 GNUNET_free (db_lib_name);
122 GNUNET_SCHEDULER_shutdown ();
123 return;
124 }
125 }
126 if (init || reset)
127 {
128 if (GNUNET_OK !=
129 plugin->create_tables (plugin->cls))
130 {
131 fprintf (stderr,
132 "Failed to initialize database\n");
133 ret = 1;
134 GNUNET_free (db_lib_name);
135 GNUNET_SCHEDULER_shutdown ();
136 return;
137 }
138 }
139 GNUNET_SCHEDULER_shutdown ();
140 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
141 plugin));
142 GNUNET_free (db_lib_name);
143}
144
145
146/**
147 * The main function for gnunet-namestore-dbtool.
148 *
149 * @param argc number of arguments from the command line
150 * @param argv command line arguments
151 * @return 0 ok, 1 on error
152 */
153int
154main (int argc, char *const *argv)
155{
156 struct GNUNET_GETOPT_CommandLineOption options[] = {
157 GNUNET_GETOPT_option_flag ('i', "init",
158 gettext_noop ("initialize database"),
159 &init),
160 GNUNET_GETOPT_option_flag ('r',
161 "reset",
162 gettext_noop (
163 "reset database (DANGEROUS: All existing data is lost!"),
164 &reset),
165 GNUNET_GETOPT_option_string (
166 'p',
167 "plugin",
168 "PLUGIN",
169 gettext_noop (
170 "the namestore plugin to work with, e.g. 'sqlite'"),
171 &pluginname),
172 GNUNET_GETOPT_OPTION_END
173 };
174 int lret;
175
176 if (GNUNET_OK !=
177 GNUNET_STRINGS_get_utf8_args (argc, argv,
178 &argc, &argv))
179 return 2;
180
181 GNUNET_log_setup ("gnunet-namestore-dbtool",
182 "WARNING",
183 NULL);
184 if (GNUNET_OK !=
185 (lret = GNUNET_PROGRAM_run (argc,
186 argv,
187 "gnunet-namestore-dbtool",
188 _ (
189 "GNUnet namestore database manipulation tool"),
190 options,
191 &run,
192 NULL)))
193 {
194 GNUNET_free_nz ((void *) argv);
195 return lret;
196 }
197 GNUNET_free_nz ((void *) argv);
198 return ret;
199}
diff --git a/src/cli/namestore/gnunet-namestore-zonefile.c b/src/cli/namestore/gnunet-namestore-zonefile.c
new file mode 100644
index 000000000..d43e88006
--- /dev/null
+++ b/src/cli/namestore/gnunet-namestore-zonefile.c
@@ -0,0 +1,729 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2019, 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 gnunet-namestore-dbtool.c
22 * @brief command line tool to manipulate the database backends for the namestore
23 * @author Martin Schanzenbach
24 *
25 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
28#include <gnunet_namestore_plugin.h>
29
30#define MAX_RECORDS_PER_NAME 50
31
32/**
33 * Maximum length of a zonefile line
34 */
35#define MAX_ZONEFILE_LINE_LEN 4096
36
37/**
38 * FIXME: Soft limit this?
39 */
40#define MAX_ZONEFILE_RECORD_DATA_LEN 2048
41
42/**
43 * The record data under a single label. Reused.
44 * Hard limit.
45 */
46static struct GNUNET_GNSRECORD_Data rd[MAX_RECORDS_PER_NAME];
47
48/**
49 * Current record $TTL to use
50 */
51static struct GNUNET_TIME_Relative ttl;
52
53/**
54 * Current origin
55 */
56static char origin[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
57
58/**
59 * Number of records for currently parsed set
60 */
61static unsigned int rd_count = 0;
62
63/**
64 * Return code
65 */
66static int ret = 0;
67
68/**
69 * Name of the ego
70 */
71static char *ego_name = NULL;
72
73/**
74 * Currently read line or NULL on EOF
75 */
76static char *res;
77
78/**
79 * Statistics, how many published record sets
80 */
81static unsigned int published_sets = 0;
82
83/**
84 * Statistics, how many records published in aggregate
85 */
86static unsigned int published_records = 0;
87
88
89/**
90 * Handle to identity lookup.
91 */
92static struct GNUNET_IDENTITY_EgoLookup *el;
93
94/**
95 * Private key for the our zone.
96 */
97static struct GNUNET_CRYPTO_PrivateKey zone_pkey;
98
99/**
100 * Queue entry for the 'add' operation.
101 */
102static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
103
104/**
105 * Handle to the namestore.
106 */
107static struct GNUNET_NAMESTORE_Handle *ns;
108
109/**
110 * Origin create operations
111 */
112static struct GNUNET_IDENTITY_Operation *id_op;
113
114/**
115 * Handle to IDENTITY
116 */
117static struct GNUNET_IDENTITY_Handle *id;
118
119/**
120 * Current configurataion
121 */
122static const struct GNUNET_CONFIGURATION_Handle *cfg;
123
124/**
125 * Scheduled parse task
126 */
127static struct GNUNET_SCHEDULER_Task *parse_task;
128
129/**
130 * The current state of the parser
131 */
132static int state;
133
134enum ZonefileImportState
135{
136
137 /* Uninitialized */
138 ZS_READY,
139
140 /* The initial state */
141 ZS_ORIGIN_SET,
142
143 /* The $ORIGIN has changed */
144 ZS_ORIGIN_CHANGED,
145
146 /* The record name/label has changed */
147 ZS_NAME_CHANGED
148
149};
150
151
152
153/**
154 * Task run on shutdown. Cleans up everything.
155 *
156 * @param cls unused
157 */
158static void
159do_shutdown (void *cls)
160{
161 (void) cls;
162 if (NULL != ego_name)
163 GNUNET_free (ego_name);
164 if (NULL != el)
165 {
166 GNUNET_IDENTITY_ego_lookup_cancel (el);
167 el = NULL;
168 }
169 if (NULL != ns_qe)
170 GNUNET_NAMESTORE_cancel (ns_qe);
171 if (NULL != id_op)
172 GNUNET_IDENTITY_cancel (id_op);
173 if (NULL != ns)
174 GNUNET_NAMESTORE_disconnect (ns);
175 if (NULL != id)
176 GNUNET_IDENTITY_disconnect (id);
177 for (int i = 0; i < rd_count; i++)
178 {
179 void *rd_ptr = (void*) rd[i].data;
180 GNUNET_free (rd_ptr);
181 }
182 if (NULL != parse_task)
183 GNUNET_SCHEDULER_cancel (parse_task);
184}
185
186static void
187parse (void *cls);
188
189static char*
190trim (char *line)
191{
192 char *ltrimmed = line;
193 int ltrimmed_len;
194 int quoted = 0;
195
196 // Trim all whitespace to the left
197 while (*ltrimmed == ' ')
198 ltrimmed++;
199 ltrimmed_len = strlen (ltrimmed);
200 // Find the first occurence of an unqoted ';', which is our comment
201 for (int i = 0; i < ltrimmed_len; i++)
202 {
203 if (ltrimmed[i] == '"')
204 quoted = ! quoted;
205 if ((ltrimmed[i] != ';') || quoted)
206 continue;
207 ltrimmed[i] = '\0';
208 }
209 ltrimmed_len = strlen (ltrimmed);
210 // Remove trailing whitespace
211 for (int i = ltrimmed_len; i > 0; i--)
212 {
213 if (ltrimmed[i - 1] != ' ')
214 break;
215 ltrimmed[i - 1] = '\0';
216 }
217 ltrimmed_len = strlen (ltrimmed);
218 if (ltrimmed[ltrimmed_len - 1] == '\n')
219 ltrimmed[ltrimmed_len - 1] = ' ';
220 return ltrimmed;
221}
222
223static char*
224next_token (char *token)
225{
226 char *next = token;
227 while (*next == ' ')
228 next++;
229 return next;
230}
231
232static int
233parse_ttl (char *token, struct GNUNET_TIME_Relative *ttl)
234{
235 char *next;
236 unsigned int ttl_tmp;
237
238 next = strchr (token, ';');
239 if (NULL != next)
240 next[0] = '\0';
241 next = strchr (token, ' ');
242 if (NULL != next)
243 next[0] = '\0';
244 if (1 != sscanf (token, "%u", &ttl_tmp))
245 {
246 fprintf (stderr, "Unable to parse TTL `%s'\n", token);
247 return GNUNET_SYSERR;
248 }
249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TTL is: %u\n", ttl_tmp);
250 ttl->rel_value_us = ttl_tmp * 1000 * 1000;
251 return GNUNET_OK;
252}
253
254static int
255parse_origin (char *token, char *origin)
256{
257 char *next;
258 next = strchr (token, ';');
259 if (NULL != next)
260 next[0] = '\0';
261 next = strchr (token, ' ');
262 if (NULL != next)
263 next[0] = '\0';
264 strcpy (origin, token);
265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin is: %s\n", origin);
266 return GNUNET_OK;
267}
268
269static void
270origin_create_cb (void *cls, const struct GNUNET_CRYPTO_PrivateKey *pk,
271 enum GNUNET_ErrorCode ec)
272{
273 id_op = NULL;
274 if (GNUNET_EC_NONE != ec)
275 {
276 fprintf (stderr, "Error: %s\n", GNUNET_ErrorCode_get_hint (ec));
277 ret = 1;
278 GNUNET_SCHEDULER_shutdown ();
279 return;
280 }
281 state = ZS_ORIGIN_SET;
282 zone_pkey = *pk;
283 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
284}
285
286static void
287origin_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
288{
289
290 el = NULL;
291
292 if (NULL == ego)
293 {
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "$ORIGIN %s does not exist, creating...\n", ego_name);
296 id_op = GNUNET_IDENTITY_create (id, ego_name, NULL,
297 GNUNET_PUBLIC_KEY_TYPE_ECDSA, // FIXME make configurable
298 origin_create_cb,
299 NULL);
300 return;
301 }
302 state = ZS_ORIGIN_SET;
303 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
304 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
305}
306
307static void
308add_continuation (void *cls, enum GNUNET_ErrorCode ec)
309{
310 ns_qe = NULL;
311 if (GNUNET_EC_NONE != ec)
312 {
313 fprintf (stderr,
314 _ ("Failed to store records...\n"));
315 GNUNET_SCHEDULER_shutdown ();
316 ret = -1;
317 }
318 if (ZS_ORIGIN_CHANGED == state)
319 {
320 if (NULL != ego_name)
321 GNUNET_free (ego_name);
322 ego_name = GNUNET_strdup (origin);
323 if (ego_name[strlen (ego_name) - 1] == '.')
324 ego_name[strlen (ego_name) - 1] = '\0';
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326 "Changing origin to %s\n", ego_name);
327 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name,
328 &origin_lookup_cb, NULL);
329 return;
330 }
331 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
332}
333
334
335
336/**
337 * Main function that will be run.
338 *
339 * TODO:
340 * - We must assume that names are not repeated later in the zonefile because
341 * our _store APIs are replacing. No sure if that is common in zonefiles.
342 * - We must only actually store a record set when the name to store changes or
343 * the end of the file is reached.
344 * that way we can group them and add (see above).
345 * - We need to hope our string formats are compatible, but seems ok.
346 *
347 * @param cls closure
348 * @param args remaining command-line arguments
349 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
350 * @param cfg configuration
351 */
352static void
353parse (void *cls)
354{
355 char buf[MAX_ZONEFILE_LINE_LEN];
356 char payload[MAX_ZONEFILE_RECORD_DATA_LEN];
357 char *next;
358 char *token;
359 char *payload_pos;
360 static char lastname[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
361 char newname[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
362 void *data;
363 size_t data_size;
364 int ttl_line = 0;
365 int type;
366 int bracket_unclosed = 0;
367 int quoted = 0;
368
369 parse_task = NULL;
370 /* use filename provided as 1st argument (stdin by default) */
371 int ln = 0;
372 while ((res = fgets (buf, sizeof(buf), stdin))) /* read each line of input */
373 {
374 ln++;
375 ttl_line = 0;
376 token = trim (buf);
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Trimmed line (bracket %s): `%s'\n",
379 (bracket_unclosed > 0) ? "unclosed" : "closed",
380 token);
381 if ((0 == strlen (token)) ||
382 ((1 == strlen (token)) && (' ' == *token)))
383 continue; // I guess we can safely ignore blank lines
384 if (bracket_unclosed == 0)
385 {
386 /* Payload is already parsed */
387 payload_pos = payload;
388 /* Find space */
389 next = strchr (token, ' ');
390 if (NULL == next)
391 {
392 fprintf (stderr, "Error at line %u: %s\n", ln, token);
393 ret = 1;
394 GNUNET_SCHEDULER_shutdown ();
395 return;
396 }
397 next[0] = '\0';
398 next++;
399 if (0 == (strcmp (token, "$ORIGIN")))
400 {
401 state = ZS_ORIGIN_CHANGED;
402 token = next_token (next);
403 }
404 else if (0 == (strcmp (token, "$TTL")))
405 {
406 ttl_line = 1;
407 token = next_token (next);
408 }
409 else
410 {
411 if (0 == strcmp (token, "IN")) // Inherit name from before
412 {
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Old name: %s\n", lastname);
415 strcpy (newname, lastname);
416 token[strlen (token)] = ' ';
417 }
418 else if (token[strlen (token) - 1] != '.') // no fqdn
419 {
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: %s\n", token);
421 if (GNUNET_DNSPARSER_MAX_LABEL_LENGTH < strlen (token))
422 {
423 fprintf (stderr,
424 _ ("Name `%s' is too long\n"),
425 token);
426 ret = 1;
427 GNUNET_SCHEDULER_shutdown ();
428 return;
429 }
430 strcpy (newname, token);
431 token = next_token (next);
432 }
433 else if (0 == strcmp (token, origin))
434 {
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: @\n");
436 strcpy (newname, "@");
437 token = next_token (next);
438 }
439 else
440 {
441 if (strlen (token) < strlen (origin))
442 {
443 fprintf (stderr, "Wrong origin: %s (expected %s)\n", token, origin);
444 break; // FIXME error?
445 }
446 if (0 != strcmp (token + (strlen (token) - strlen (origin)), origin))
447 {
448 fprintf (stderr, "Wrong origin: %s (expected %s)\n", token, origin);
449 break;
450 }
451 token[strlen (token) - strlen (origin) - 1] = '\0';
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: %s\n", token);
453 if (GNUNET_DNSPARSER_MAX_LABEL_LENGTH < strlen (token))
454 {
455 fprintf (stderr,
456 _ ("Name `%s' is too long\n"),
457 token);
458 ret = 1;
459 GNUNET_SCHEDULER_shutdown ();
460 return;
461 }
462 strcpy (newname, token);
463 token = next_token (next);
464 }
465 if (0 != strcmp (newname, lastname) &&
466 (0 < rd_count))
467 {
468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
469 "Name changed %s->%s, storing record set of %u elements\n",
470 lastname, newname,
471 rd_count);
472 state = ZS_NAME_CHANGED;
473 }
474 else {
475 strcpy (lastname, newname);
476 }
477 }
478
479 if (ttl_line)
480 {
481 if (GNUNET_SYSERR == parse_ttl (token, &ttl))
482 {
483 fprintf (stderr, _ ("Failed to parse $TTL\n"));
484 ret = 1;
485 GNUNET_SCHEDULER_shutdown ();
486 return;
487 }
488 continue;
489 }
490 if (ZS_ORIGIN_CHANGED == state)
491 {
492 if (GNUNET_SYSERR == parse_origin (token, origin))
493 {
494 fprintf (stderr, _ ("Failed to parse $ORIGIN from %s\n"), token);
495 ret = 1;
496 GNUNET_SCHEDULER_shutdown ();
497 return;
498 }
499 break;
500 }
501 if (ZS_READY == state)
502 {
503 fprintf (stderr,
504 _ (
505 "You must provide $ORIGIN in your zonefile or via arguments (--zone)!\n"));
506 ret = 1;
507 GNUNET_SCHEDULER_shutdown ();
508 return;
509 }
510 // This is a record, let's go
511 if (MAX_RECORDS_PER_NAME == rd_count)
512 {
513 fprintf (stderr,
514 _ ("Only %u records per unique name supported.\n"),
515 MAX_RECORDS_PER_NAME);
516 ret = 1;
517 GNUNET_SCHEDULER_shutdown ();
518 return;
519 }
520 rd[rd_count].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
521 rd[rd_count].expiration_time = ttl.rel_value_us;
522 next = strchr (token, ' ');
523 if (NULL == next)
524 {
525 fprintf (stderr, "Error, last token: %s\n", token);
526 ret = 1;
527 GNUNET_SCHEDULER_shutdown ();
528 break;
529 }
530 next[0] = '\0';
531 next++;
532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "class is: %s\n", token);
533 while (*next == ' ')
534 next++;
535 token = next;
536 next = strchr (token, ' ');
537 if (NULL == next)
538 {
539 fprintf (stderr, "Error\n");
540 break;
541 }
542 next[0] = '\0';
543 next++;
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "type is: %s\n", token);
545 type = GNUNET_GNSRECORD_typename_to_number (token);
546 rd[rd_count].record_type = type;
547 while (*next == ' ')
548 next++;
549 token = next;
550 }
551 for (int i = 0; i < strlen (token); i++)
552 {
553 if (token[i] == '"')
554 quoted = ! quoted;
555 if ((token[i] == '(') && ! quoted)
556 bracket_unclosed++;
557 if ((token[i] == ')') && ! quoted)
558 bracket_unclosed--;
559 }
560 memcpy (payload_pos, token, strlen (token));
561 payload_pos += strlen (token);
562 if (bracket_unclosed > 0)
563 {
564 *payload_pos = ' ';
565 payload_pos++;
566 continue;
567 }
568 *payload_pos = '\0';
569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "data is: %s\n\n", payload);
570 if (GNUNET_OK !=
571 GNUNET_GNSRECORD_string_to_value (type, payload,
572 &data,
573 &data_size))
574 {
575 fprintf (stderr,
576 _ ("Data `%s' invalid\n"),
577 payload);
578 ret = 1;
579 GNUNET_SCHEDULER_shutdown ();
580 return;
581 }
582 rd[rd_count].data = data;
583 rd[rd_count].data_size = data_size;
584 if (ZS_NAME_CHANGED == state)
585 break;
586 rd_count++;
587 }
588 if (rd_count > 0)
589 {
590 ns_qe = GNUNET_NAMESTORE_record_set_store (ns,
591 &zone_pkey,
592 lastname,
593 rd_count,
594 rd,
595 &add_continuation,
596 NULL);
597 published_sets++;
598 published_records += rd_count;
599 for (int i = 0; i < rd_count; i++)
600 {
601 data = (void*) rd[i].data;
602 GNUNET_free (data);
603 }
604 if (ZS_NAME_CHANGED == state)
605 {
606 rd[0] = rd[rd_count]; // recover last rd parsed.
607 rd_count = 1;
608 strcpy (lastname, newname);
609 state = ZS_ORIGIN_SET;
610 }
611 else
612 rd_count = 0;
613 return;
614 }
615 if (ZS_ORIGIN_CHANGED == state)
616 {
617 if (NULL != ego_name)
618 GNUNET_free (ego_name);
619 ego_name = GNUNET_strdup (origin);
620 if (ego_name[strlen (ego_name) - 1] == '.')
621 ego_name[strlen (ego_name) - 1] = '\0';
622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
623 "Changing origin to %s\n", ego_name);
624 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name,
625 &origin_lookup_cb, NULL);
626 return;
627 }
628 printf ("Published %u records sets with total %u records\n",
629 published_sets, published_records);
630 GNUNET_SCHEDULER_shutdown ();
631}
632
633
634static void
635identity_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
636{
637
638 el = NULL;
639 if (NULL == ego)
640 {
641 if (NULL != ego_name)
642 {
643 fprintf (stderr,
644 _ ("Ego `%s' not known to identity service\n"),
645 ego_name);
646
647 }
648 GNUNET_SCHEDULER_shutdown ();
649 ret = -1;
650 return;
651 }
652 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
653 sprintf (origin, "%s.", ego_name);
654 state = ZS_ORIGIN_SET;
655 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
656}
657
658
659static void
660run (void *cls,
661 char *const *args,
662 const char *cfgfile,
663 const struct GNUNET_CONFIGURATION_Handle *_cfg)
664{
665 cfg = _cfg;
666 ns = GNUNET_NAMESTORE_connect (cfg);
667 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
668 if (NULL == ns)
669 {
670 fprintf (stderr,
671 _ ("Failed to connect to NAMESTORE\n"));
672 return;
673 }
674 id = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
675 if (NULL == id)
676 {
677 fprintf (stderr,
678 _ ("Failed to connect to IDENTITY\n"));
679 return;
680 }
681 if (NULL != ego_name)
682 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &identity_cb, (void *) cfg);
683 else
684 parse_task = GNUNET_SCHEDULER_add_now (&parse, NULL);
685 state = ZS_READY;
686}
687
688
689/**
690 * The main function for gnunet-namestore-dbtool.
691 *
692 * @param argc number of arguments from the command line
693 * @param argv command line arguments
694 * @return 0 ok, 1 on error
695 */
696int
697main (int argc, char *const *argv)
698{
699 struct GNUNET_GETOPT_CommandLineOption options[] = {
700 GNUNET_GETOPT_option_string ('z',
701 "zone",
702 "EGO",
703 gettext_noop (
704 "name of the ego controlling the zone"),
705 &ego_name),
706 GNUNET_GETOPT_OPTION_END
707 };
708 int lret;
709
710 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
711 return 2;
712
713 GNUNET_log_setup ("gnunet-namestore-dbtool", "WARNING", NULL);
714 if (GNUNET_OK !=
715 (lret = GNUNET_PROGRAM_run (argc,
716 argv,
717 "gnunet-namestore-zonefile",
718 _ (
719 "GNUnet namestore database manipulation tool"),
720 options,
721 &run,
722 NULL)))
723 {
724 GNUNET_free_nz ((void *) argv);
725 return lret;
726 }
727 GNUNET_free_nz ((void *) argv);
728 return ret;
729}
diff --git a/src/cli/namestore/gnunet-namestore.c b/src/cli/namestore/gnunet-namestore.c
new file mode 100644
index 000000000..6c0890a43
--- /dev/null
+++ b/src/cli/namestore/gnunet-namestore.c
@@ -0,0 +1,2118 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2019 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 gnunet-namestore.c
22 * @brief command line tool to manipulate the local zone
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - test
27 */
28#include "platform.h"
29#include <gnunet_util_lib.h>
30#include <gnunet_identity_service.h>
31#include <gnunet_gnsrecord_lib.h>
32#include <gnunet_gns_service.h>
33#include <gnunet_namestore_service.h>
34#include <inttypes.h>
35
36/**
37 * The upper bound for the zone iteration interval
38 * (per record).
39 */
40#define WARN_RELATIVE_EXPIRATION_LIMIT GNUNET_TIME_relative_multiply ( \
41 GNUNET_TIME_UNIT_MINUTES, 15)
42
43/**
44 * Entry in record set for bulk processing.
45 */
46struct RecordSetEntry
47{
48 /**
49 * Kept in a linked list.
50 */
51 struct RecordSetEntry *next;
52
53 /**
54 * The record to add/remove.
55 */
56 struct GNUNET_GNSRECORD_Data record;
57};
58
59/**
60 * The record marked for deletion
61 */
62struct MarkedRecord
63{
64 /**
65 * DLL
66 */
67 struct MarkedRecord *next;
68
69 /**
70 * DLL
71 */
72 struct MarkedRecord *prev;
73
74 /**
75 * Ego Identifier
76 */
77 char *name;
78
79 /**
80 * The zone key
81 */
82 struct GNUNET_CRYPTO_PrivateKey key;
83};
84
85/**
86 * The default namestore ego
87 */
88struct EgoEntry
89{
90 /**
91 * DLL
92 */
93 struct EgoEntry *next;
94
95 /**
96 * DLL
97 */
98 struct EgoEntry *prev;
99
100 /**
101 * Ego Identifier
102 */
103 char *identifier;
104
105 /**
106 * The Ego
107 */
108 struct GNUNET_IDENTITY_Ego *ego;
109};
110
111/**
112 * Handle to the namestore.
113 */
114static struct GNUNET_NAMESTORE_Handle *ns;
115
116/**
117 * Private key for the our zone.
118 */
119static struct GNUNET_CRYPTO_PrivateKey zone_pkey;
120
121/**
122 * Identity service handle
123 */
124static struct GNUNET_IDENTITY_Handle *idh;
125
126/**
127 * Name of the ego controlling the zone.
128 */
129static char *ego_name;
130
131/**
132 * Queue entry for the 'add-uri' operation.
133 */
134static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
135
136/**
137 * Queue entry for the 'add' operation.
138 */
139static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
140
141/**
142 * Queue entry for the 'lookup' operation.
143 */
144static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
145
146/**
147 * Queue entry for the 'reverse lookup' operation (in combination with a name).
148 */
149static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
150
151/**
152 * Marked record list
153 */
154static struct MarkedRecord *marked_head;
155
156/**
157 * Marked record list
158 */
159static struct MarkedRecord *marked_tail;
160
161/**
162 * Configuration handle
163 */
164const struct GNUNET_CONFIGURATION_Handle *cfg;
165
166/**
167 * Ego list
168 */
169static struct EgoEntry *ego_head;
170
171/**
172 * Ego list
173 */
174static struct EgoEntry *ego_tail;
175
176/**
177 * List iterator for the 'list' operation.
178 */
179static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
180
181/**
182 * Run in read from stdin mode.
183 */
184static int read_from_stdin;
185
186/**
187 * Desired action is to list records.
188 */
189static int list;
190
191/**
192 * Desired action is to add a record.
193 */
194static int add;
195
196/**
197 * Desired action is to remove a record.
198 */
199static int del;
200
201/**
202 * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
203 */
204static int is_public;
205
206/**
207 * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW)
208 */
209static int is_shadow;
210
211/**
212 * Is record a maintenance record (#GNUNET_GNSRECORD_RF_MAINTENANCE)
213 */
214static int is_maintenance;
215
216/**
217 * Filter private records
218 */
219static int omit_private;
220
221/**
222 * Output in recordline format
223 */
224static int output_recordline;
225
226
227/**
228 * Purge zone contents
229 */
230static int purge_zone;
231
232/**
233 * Do not filter maintenance records
234 */
235static int include_maintenance;
236
237/**
238 * Purge orphaned records
239 */
240static int purge_orphaned;
241
242/**
243 * List records and zone keys of orphaned records
244 */
245static int list_orphaned;
246
247/**
248 * Queue entry for the 'del' operation.
249 */
250static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
251
252/**
253 * Queue entry for the 'set/replace' operation.
254 */
255static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
256
257/**
258 * Queue entry for begin/commit
259 */
260static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
261
262/**
263 * Name of the records to add/list/remove.
264 */
265static char *name;
266
267/**
268 * Value of the record to add/remove.
269 */
270static char *value;
271
272/**
273 * URI to import.
274 */
275static char *uri;
276
277/**
278 * Reverse lookup to perform.
279 */
280static char *reverse_pkey;
281
282/**
283 * Type of the record to add/remove, NULL to remove all.
284 */
285static char *typestring;
286
287/**
288 * Desired expiration time.
289 */
290static char *expirationstring;
291
292/**
293 * Desired nick name.
294 */
295static char *nickstring;
296
297/**
298 * Global return value
299 */
300static int ret;
301
302/**
303 * Type string converted to DNS type value.
304 */
305static uint32_t type;
306
307/**
308 * Value in binary format.
309 */
310static void *data;
311
312/**
313 * Number of bytes in #data.
314 */
315static size_t data_size;
316
317/**
318 * Expiration string converted to numeric value.
319 */
320static uint64_t etime;
321
322/**
323 * Is expiration time relative or absolute time?
324 */
325static int etime_is_rel = GNUNET_SYSERR;
326
327/**
328 * Monitor handle.
329 */
330static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
331
332/**
333 * Enables monitor mode.
334 */
335static int monitor;
336
337/**
338 * Entry in record set for processing records in bulk.
339 */
340static struct RecordSetEntry *recordset;
341
342/**
343 * Purge task
344 */
345static struct GNUNET_SCHEDULER_Task *purge_task;
346
347/**
348 * Parse expiration time.
349 *
350 * @param expirationstring text to parse
351 * @param[out] etime_is_rel set to #GNUNET_YES if time is relative
352 * @param[out] etime set to expiration time (abs or rel)
353 * @return #GNUNET_OK on success
354 */
355static int
356parse_expiration (const char *expirationstring,
357 int *etime_is_rel,
358 uint64_t *etime)
359{
360 struct GNUNET_TIME_Relative etime_rel;
361 struct GNUNET_TIME_Absolute etime_abs;
362
363 if (0 == strcmp (expirationstring, "never"))
364 {
365 *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
366 *etime_is_rel = GNUNET_NO;
367 return GNUNET_OK;
368 }
369 if (GNUNET_OK ==
370 GNUNET_STRINGS_fancy_time_to_relative (expirationstring, &etime_rel))
371 {
372 *etime_is_rel = GNUNET_YES;
373 *etime = etime_rel.rel_value_us;
374 if (GNUNET_TIME_relative_cmp (etime_rel, <, WARN_RELATIVE_EXPIRATION_LIMIT))
375 {
376 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
377 "Relative expiration times of less than %s are not recommended. To improve availability, consider increasing this value.\n",
378 GNUNET_STRINGS_relative_time_to_string (
379 WARN_RELATIVE_EXPIRATION_LIMIT, GNUNET_NO));
380 }
381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382 "Storing record with relative expiration time of %s\n",
383 GNUNET_STRINGS_relative_time_to_string (etime_rel, GNUNET_NO));
384 return GNUNET_OK;
385 }
386 if (GNUNET_OK ==
387 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, &etime_abs))
388 {
389 *etime_is_rel = GNUNET_NO;
390 *etime = etime_abs.abs_value_us;
391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
392 "Storing record with absolute expiration time of %s\n",
393 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
394 return GNUNET_OK;
395 }
396 return GNUNET_SYSERR;
397}
398
399
400static int
401parse_recordline (const char *line)
402{
403 struct RecordSetEntry **head = &recordset;
404 struct RecordSetEntry *r;
405 struct GNUNET_GNSRECORD_Data record;
406 char *cp;
407 char *tok;
408 char *saveptr;
409 void *raw_data;
410
411 cp = GNUNET_strdup (line);
412 tok = strtok_r (cp, " ", &saveptr);
413 if (NULL == tok)
414 {
415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
416 _ ("Missing entries in record line `%s'.\n"),
417 line);
418 GNUNET_free (cp);
419 return GNUNET_SYSERR;
420 }
421 record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
422 if (UINT32_MAX == record.record_type)
423 {
424 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Unknown record type `%s'\n"), tok);
425 GNUNET_free (cp);
426 return GNUNET_SYSERR;
427 }
428 tok = strtok_r (NULL, " ", &saveptr);
429 if (NULL == tok)
430 {
431 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432 _ ("Empty record line argument is not allowed.\n"));
433 GNUNET_free (cp);
434 return GNUNET_SYSERR;
435 }
436 if (1 != sscanf (tok, "%" SCNu64, &record.expiration_time))
437 {
438 fprintf (stderr,
439 _ ("Error parsing expiration time %s.\n"), tok);
440 GNUNET_free (cp);
441 return GNUNET_SYSERR;
442 }
443 tok = strtok_r (NULL, " ", &saveptr);
444 if (NULL == tok)
445 {
446 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
447 _ ("Empty record line argument is not allowed.\n"));
448 GNUNET_free (cp);
449 return GNUNET_SYSERR;
450 }
451 record.flags = GNUNET_GNSRECORD_RF_NONE;
452 if (NULL != strchr (tok, (unsigned char) 'r'))
453 record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
454 if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
455 record.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
456 if (NULL != strchr (tok, (unsigned char) 'S'))
457 record.flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
458 if (NULL != strchr (tok, (unsigned char) 's'))
459 record.flags |= GNUNET_GNSRECORD_RF_SHADOW;
460 if (NULL != strchr (tok, (unsigned char) 'C'))
461 record.flags |= GNUNET_GNSRECORD_RF_CRITICAL;
462 tok += strlen (tok) + 1;
463 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record.record_type,
464 tok,
465 &raw_data,
466 &record.data_size))
467 {
468 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
469 _ ("Invalid record data for type %s: `%s'.\n"),
470 GNUNET_GNSRECORD_number_to_typename (record.record_type),
471 tok);
472 GNUNET_free (cp);
473 return GNUNET_SYSERR;
474 }
475 GNUNET_free (cp);
476
477 r = GNUNET_malloc (sizeof(struct RecordSetEntry) + record.data_size);
478 r->next = *head;
479 record.data = &r[1];
480 memcpy (&r[1], raw_data, record.data_size);
481 GNUNET_free (raw_data);
482 r->record = record;
483 *head = r;
484 return GNUNET_OK;
485}
486
487
488static void
489reset_handles (void)
490{
491 struct MarkedRecord *mrec;
492 struct MarkedRecord *mrec_tmp;
493 struct RecordSetEntry *rs_entry;
494
495 rs_entry = recordset;
496 while (NULL != (rs_entry = recordset))
497 {
498 recordset = recordset->next;
499 GNUNET_free (rs_entry);
500 }
501 recordset = NULL;
502 if (NULL != ego_name)
503 {
504 GNUNET_free (ego_name);
505 ego_name = NULL;
506 }
507 if (NULL != name)
508 {
509 GNUNET_free (name);
510 name = NULL;
511 }
512 if (NULL != value)
513 {
514 GNUNET_free (value);
515 value = NULL;
516 }
517 if (NULL != uri)
518 {
519 GNUNET_free (uri);
520 uri = NULL;
521 }
522 if (NULL != expirationstring)
523 {
524 GNUNET_free (expirationstring);
525 expirationstring = NULL;
526 }
527 if (NULL != purge_task)
528 {
529 GNUNET_SCHEDULER_cancel (purge_task);
530 purge_task = NULL;
531 }
532 for (mrec = marked_head; NULL != mrec;)
533 {
534 mrec_tmp = mrec;
535 mrec = mrec->next;
536 GNUNET_free (mrec_tmp->name);
537 GNUNET_free (mrec_tmp);
538 }
539 if (NULL != list_it)
540 {
541 GNUNET_NAMESTORE_zone_iteration_stop (list_it);
542 list_it = NULL;
543 }
544 if (NULL != add_qe)
545 {
546 GNUNET_NAMESTORE_cancel (add_qe);
547 add_qe = NULL;
548 }
549 if (NULL != set_qe)
550 {
551 GNUNET_NAMESTORE_cancel (set_qe);
552 set_qe = NULL;
553 }
554 if (NULL != add_qe_uri)
555 {
556 GNUNET_NAMESTORE_cancel (add_qe_uri);
557 add_qe_uri = NULL;
558 }
559 if (NULL != get_qe)
560 {
561 GNUNET_NAMESTORE_cancel (get_qe);
562 get_qe = NULL;
563 }
564 if (NULL != del_qe)
565 {
566 GNUNET_NAMESTORE_cancel (del_qe);
567 del_qe = NULL;
568 }
569 if (NULL != reverse_qe)
570 {
571 GNUNET_NAMESTORE_cancel (reverse_qe);
572 reverse_qe = NULL;
573 }
574 memset (&zone_pkey, 0, sizeof(zone_pkey));
575 if (NULL != zm)
576 {
577 GNUNET_NAMESTORE_zone_monitor_stop (zm);
578 zm = NULL;
579 }
580 if (NULL != data)
581 {
582 GNUNET_free (data);
583 data = NULL;
584 }
585 if (NULL != typestring)
586 {
587 GNUNET_free (typestring);
588 typestring = NULL;
589 }
590 list = 0;
591 is_public = 0;
592 is_shadow = 0;
593 is_maintenance = 0;
594 purge_zone = 0;
595}
596
597
598/**
599 * Task run on shutdown. Cleans up everything.
600 *
601 * @param cls unused
602 */
603static void
604do_shutdown (void *cls)
605{
606 struct EgoEntry *ego_entry;
607 struct EgoEntry *ego_tmp;
608 (void) cls;
609
610 reset_handles ();
611 if (NULL != ns_qe)
612 {
613 GNUNET_NAMESTORE_cancel (ns_qe);
614 ns_qe = NULL;
615 }
616 if (NULL != ns)
617 {
618 GNUNET_NAMESTORE_disconnect (ns);
619 ns = NULL;
620 }
621 if (NULL != idh)
622 {
623 GNUNET_IDENTITY_disconnect (idh);
624 idh = NULL;
625 }
626 for (ego_entry = ego_head; NULL != ego_entry;)
627 {
628 ego_tmp = ego_entry;
629 ego_entry = ego_entry->next;
630 GNUNET_free (ego_tmp->identifier);
631 GNUNET_free (ego_tmp);
632 }
633}
634
635
636static void
637process_command_stdin ();
638
639
640static void
641finish_command (void)
642{
643 reset_handles ();
644 if (read_from_stdin)
645 {
646 process_command_stdin ();
647 return;
648 }
649 GNUNET_SCHEDULER_shutdown ();
650}
651
652
653static void
654add_continuation (void *cls, enum GNUNET_ErrorCode ec)
655{
656 struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
657
658 *qe = NULL;
659 if (GNUNET_EC_NONE != ec)
660 {
661 fprintf (stderr,
662 _ ("Adding record failed: %s\n"),
663 GNUNET_ErrorCode_get_hint (ec));
664 if (GNUNET_EC_NAMESTORE_RECORD_EXISTS != ec)
665 ret = 1;
666 }
667 ret = 0;
668 finish_command ();
669}
670
671
672static void
673del_continuation (void *cls, enum GNUNET_ErrorCode ec)
674{
675 (void) cls;
676 del_qe = NULL;
677 if (GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND == ec)
678 {
679 fprintf (stderr,
680 _ ("Deleting record failed: %s\n"), GNUNET_ErrorCode_get_hint (
681 ec));
682 }
683 finish_command ();
684}
685
686
687static void
688purge_next_record (void *cls);
689
690static void
691marked_deleted (void *cls, enum GNUNET_ErrorCode ec)
692{
693 del_qe = NULL;
694 if (GNUNET_EC_NONE != ec)
695 {
696 fprintf (stderr,
697 _ ("Deleting record failed: %s\n"),
698 GNUNET_ErrorCode_get_hint (ec));
699 }
700 purge_task = GNUNET_SCHEDULER_add_now (&purge_next_record, NULL);
701}
702
703
704static void
705purge_next_record (void *cls)
706{
707 struct MarkedRecord *mrec;
708 purge_task = NULL;
709
710 if (NULL == marked_head)
711 {
712 ret = 0;
713 finish_command ();
714 return;
715 }
716 mrec = marked_head;
717 GNUNET_CONTAINER_DLL_remove (marked_head,
718 marked_tail,
719 mrec);
720 del_qe = GNUNET_NAMESTORE_record_set_store (ns,
721 &mrec->key,
722 mrec->name,
723 0, NULL,
724 &marked_deleted,
725 NULL);
726 GNUNET_free (mrec->name);
727 GNUNET_free (mrec);
728}
729
730
731/**
732 * Function called when we are done with a zone iteration.
733 */
734static void
735zone_iteration_finished (void *cls)
736{
737 (void) cls;
738 list_it = NULL;
739 if (purge_orphaned || purge_zone)
740 {
741 purge_task = GNUNET_SCHEDULER_add_now (&purge_next_record, NULL);
742 return;
743 }
744 ret = 0;
745 finish_command ();
746}
747
748
749/**
750 * Function called when we encountered an error in a zone iteration.
751 */
752static void
753zone_iteration_error_cb (void *cls)
754{
755 (void) cls;
756 list_it = NULL;
757 fprintf (stderr, "Error iterating over zone\n");
758 ret = 1;
759 finish_command ();
760}
761
762
763static void
764collect_zone_records_to_purge (const struct
765 GNUNET_CRYPTO_PrivateKey *zone_key,
766 const char *rname,
767 unsigned int rd_len,
768 const struct GNUNET_GNSRECORD_Data *rd)
769{
770 struct MarkedRecord *mrec;
771
772 mrec = GNUNET_new (struct MarkedRecord);
773 mrec->key = *zone_key;
774 mrec->name = GNUNET_strdup (rname);
775 GNUNET_CONTAINER_DLL_insert (marked_head,
776 marked_tail,
777 mrec);
778}
779
780
781static void
782collect_orphans (const struct GNUNET_CRYPTO_PrivateKey *zone_key,
783 const char *rname,
784 unsigned int rd_len,
785 const struct GNUNET_GNSRECORD_Data *rd)
786{
787 struct EgoEntry *ego;
788 struct MarkedRecord *orphan;
789 int is_orphaned = 1;
790
791 for (ego = ego_head; NULL != ego; ego = ego->next)
792 {
793 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (ego->ego),
794 zone_key,
795 sizeof (*zone_key)))
796 {
797 is_orphaned = 0;
798 break;
799 }
800 }
801 if (is_orphaned)
802 {
803 orphan = GNUNET_new (struct MarkedRecord);
804 orphan->key = *zone_key;
805 orphan->name = GNUNET_strdup (rname);
806 GNUNET_CONTAINER_DLL_insert (marked_head,
807 marked_tail,
808 orphan);
809 }
810}
811
812
813/**
814 * Process a record that was stored in the namestore.
815 *
816 * @param rname name that is being mapped (at most 255 characters long)
817 * @param rd_len number of entries in @a rd array
818 * @param rd array of records with data to store
819 */
820static void
821display_record (const struct GNUNET_CRYPTO_PrivateKey *zone_key,
822 const char *rname,
823 unsigned int rd_len,
824 const struct GNUNET_GNSRECORD_Data *rd)
825{
826 const char *typestr;
827 char *s;
828 const char *ets;
829 struct GNUNET_TIME_Absolute at;
830 struct GNUNET_TIME_Relative rt;
831 struct EgoEntry *ego;
832 int have_record;
833 int is_orphaned = 1;
834 char *orphaned_str;
835
836 if ((NULL != name) && (0 != strcmp (name, rname)))
837 return;
838 have_record = GNUNET_NO;
839 for (unsigned int i = 0; i < rd_len; i++)
840 {
841 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
842 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
843 continue;
844 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
845 continue;
846 have_record = GNUNET_YES;
847 break;
848 }
849 if (GNUNET_NO == have_record)
850 return;
851 for (ego = ego_head; NULL != ego; ego = ego->next)
852 {
853 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (ego->ego),
854 zone_key,
855 sizeof (*zone_key)))
856 {
857 is_orphaned = 0;
858 break;
859 }
860 }
861 if (list_orphaned && ! is_orphaned)
862 return;
863 if (! list_orphaned && is_orphaned)
864 return;
865 orphaned_str = GNUNET_CRYPTO_private_key_to_string (zone_key);
866 fprintf (stdout, "%s.%s:\n", rname, is_orphaned ? orphaned_str :
867 ego->identifier);
868 GNUNET_free (orphaned_str);
869 if (NULL != typestring)
870 type = GNUNET_GNSRECORD_typename_to_number (typestring);
871 else
872 type = GNUNET_GNSRECORD_TYPE_ANY;
873 for (unsigned int i = 0; i < rd_len; i++)
874 {
875 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
876 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
877 continue;
878 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
879 continue;
880 typestr = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
881 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
882 rd[i].data,
883 rd[i].data_size);
884 if (NULL == s)
885 {
886 fprintf (stdout,
887 _ ("\tCorrupt or unsupported record of type %u\n"),
888 (unsigned int) rd[i].record_type);
889 continue;
890 }
891 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
892 {
893 rt.rel_value_us = rd[i].expiration_time;
894 ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
895 }
896 else
897 {
898 at.abs_value_us = rd[i].expiration_time;
899 ets = GNUNET_STRINGS_absolute_time_to_string (at);
900 }
901 char flgstr[16];
902 sprintf (flgstr, "[%s%s%s%s%s]",
903 (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE) ? "" : "p",
904 (rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL) ? "S" : "",
905 (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION) ? "r" : "",
906 (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW) ? "S" : "",
907 (rd[i].flags & GNUNET_GNSRECORD_RF_CRITICAL) ? "C" : "");
908 if (output_recordline)
909 fprintf (stdout,
910 " %s %" PRIu64 " %s %s\n",
911 typestr,
912 rd[i].expiration_time,
913 flgstr,
914 s);
915 else
916 fprintf (stdout,
917 "\t%s: %s (%s)\t%s\t%s\t%s\n",
918 typestr,
919 s,
920 ets,
921 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE"
922 : "PUBLIC",
923 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW)) ? "SHADOW"
924 : "",
925 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_MAINTENANCE)) ?
926 "MAINTENANCE"
927 : "");
928 GNUNET_free (s);
929 }
930 // fprintf (stdout, "%s", "\n");
931}
932
933
934static void
935purge_zone_iterator (void *cls,
936 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
937 const char *rname,
938 unsigned int rd_len,
939 const struct GNUNET_GNSRECORD_Data *rd,
940 struct GNUNET_TIME_Absolute expiry)
941{
942 (void) cls;
943 (void) zone_key;
944 (void) expiry;
945 collect_zone_records_to_purge (zone_key, rname, rd_len, rd);
946 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
947}
948
949
950static void
951purge_orphans_iterator (void *cls,
952 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
953 const char *rname,
954 unsigned int rd_len,
955 const struct GNUNET_GNSRECORD_Data *rd,
956 struct GNUNET_TIME_Absolute expiry)
957{
958 (void) cls;
959 (void) zone_key;
960 (void) expiry;
961 collect_orphans (zone_key, rname, rd_len, rd);
962 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
963}
964
965
966/**
967 * Process a record that was stored in the namestore.
968 *
969 * @param cls closure
970 * @param zone_key private key of the zone
971 * @param rname name that is being mapped (at most 255 characters long)
972 * @param rd_len number of entries in @a rd array
973 * @param rd array of records with data to store
974 */
975static void
976display_record_iterator (void *cls,
977 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
978 const char *rname,
979 unsigned int rd_len,
980 const struct GNUNET_GNSRECORD_Data *rd,
981 struct GNUNET_TIME_Absolute expiry)
982{
983 (void) cls;
984 (void) zone_key;
985 (void) expiry;
986 display_record (zone_key, rname, rd_len, rd);
987 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
988}
989
990
991/**
992 * Process a record that was stored in the namestore.
993 *
994 * @param cls closure
995 * @param zone_key private key of the zone
996 * @param rname name that is being mapped (at most 255 characters long)
997 * @param rd_len number of entries in @a rd array
998 * @param rd array of records with data to store
999 */
1000static void
1001display_record_monitor (void *cls,
1002 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1003 const char *rname,
1004 unsigned int rd_len,
1005 const struct GNUNET_GNSRECORD_Data *rd,
1006 struct GNUNET_TIME_Absolute expiry)
1007{
1008 (void) cls;
1009 (void) zone_key;
1010 (void) expiry;
1011 display_record (zone_key, rname, rd_len, rd);
1012 GNUNET_NAMESTORE_zone_monitor_next (zm, 1);
1013}
1014
1015
1016/**
1017 * Process a record that was stored in the namestore.
1018 *
1019 * @param cls closure
1020 * @param zone_key private key of the zone
1021 * @param rname name that is being mapped (at most 255 characters long)
1022 * @param rd_len number of entries in @a rd array
1023 * @param rd array of records with data to store
1024 */
1025static void
1026display_record_lookup (void *cls,
1027 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1028 const char *rname,
1029 unsigned int rd_len,
1030 const struct GNUNET_GNSRECORD_Data *rd)
1031{
1032 (void) cls;
1033 (void) zone_key;
1034 get_qe = NULL;
1035 display_record (zone_key, rname, rd_len, rd);
1036 finish_command ();
1037}
1038
1039
1040/**
1041 * Function called once we are in sync in monitor mode.
1042 *
1043 * @param cls NULL
1044 */
1045static void
1046sync_cb (void *cls)
1047{
1048 (void) cls;
1049 fprintf (stdout, "%s", "Monitor is now in sync.\n");
1050}
1051
1052
1053/**
1054 * Function called on errors while monitoring.
1055 *
1056 * @param cls NULL
1057 */
1058static void
1059monitor_error_cb (void *cls)
1060{
1061 (void) cls;
1062 fprintf (stderr, "%s", "Monitor disconnected and out of sync.\n");
1063}
1064
1065
1066/**
1067 * Function called on errors while monitoring.
1068 *
1069 * @param cls NULL
1070 */
1071static void
1072lookup_error_cb (void *cls)
1073{
1074 (void) cls;
1075 get_qe = NULL;
1076 fprintf (stderr, "%s", "Failed to lookup record.\n");
1077 finish_command ();
1078}
1079
1080
1081/**
1082 * Function called if lookup fails.
1083 */
1084static void
1085add_error_cb (void *cls)
1086{
1087 (void) cls;
1088 add_qe = NULL;
1089 GNUNET_break (0);
1090 ret = 1;
1091 finish_command ();
1092}
1093
1094
1095/**
1096 * We're storing a record; this function is given the existing record
1097 * so that we can merge the information.
1098 *
1099 * @param cls closure, unused
1100 * @param zone_key private key of the zone
1101 * @param rec_name name that is being mapped (at most 255 characters long)
1102 * @param rd_count number of entries in @a rd array
1103 * @param rd array of records with data to store
1104 */
1105static void
1106get_existing_record (void *cls,
1107 const struct GNUNET_CRYPTO_PrivateKey *zone_key,
1108 const char *rec_name,
1109 unsigned int rd_count,
1110 const struct GNUNET_GNSRECORD_Data *rd)
1111{
1112 struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
1113 struct GNUNET_GNSRECORD_Data *rde;
1114
1115 (void) cls;
1116 (void) zone_key;
1117 add_qe = NULL;
1118 if (0 != strcmp (rec_name, name))
1119 {
1120 GNUNET_break (0);
1121 ret = 1;
1122 finish_command ();
1123 return;
1124 }
1125
1126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1127 "Received %u records for name `%s'\n",
1128 rd_count,
1129 rec_name);
1130 for (unsigned int i = 0; i < rd_count; i++)
1131 {
1132 switch (rd[i].record_type)
1133 {
1134 case GNUNET_DNSPARSER_TYPE_SOA:
1135 if (GNUNET_DNSPARSER_TYPE_SOA == type)
1136 {
1137 fprintf (
1138 stderr,
1139 _ (
1140 "A SOA record exists already under `%s', cannot add a second SOA to the same zone.\n"),
1141 rec_name);
1142 ret = 1;
1143 finish_command ();
1144 return;
1145 }
1146 break;
1147 }
1148 }
1149 memset (rdn, 0, sizeof(struct GNUNET_GNSRECORD_Data));
1150 GNUNET_memcpy (&rdn[1], rd, rd_count * sizeof(struct GNUNET_GNSRECORD_Data));
1151 rde = &rdn[0];
1152 rde->data = data;
1153 rde->data_size = data_size;
1154 rde->record_type = type;
1155 if (1 == is_shadow)
1156 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW;
1157 if (1 == is_maintenance)
1158 rde->flags |= GNUNET_GNSRECORD_RF_MAINTENANCE;
1159 if (1 != is_public)
1160 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1161 rde->expiration_time = etime;
1162 if (GNUNET_YES == etime_is_rel)
1163 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1164 else if (GNUNET_NO != etime_is_rel)
1165 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
1166 GNUNET_assert (NULL != name);
1167 add_qe = GNUNET_NAMESTORE_record_set_store (ns,
1168 &zone_pkey,
1169 name,
1170 rd_count + 1,
1171 rde,
1172 &add_continuation,
1173 &add_qe);
1174}
1175
1176
1177/**
1178 * Function called if we encountered an error in zone-to-name.
1179 */
1180static void
1181reverse_error_cb (void *cls)
1182{
1183 (void) cls;
1184 reverse_qe = NULL;
1185 fprintf (stdout, "%s.zkey\n", reverse_pkey);
1186}
1187
1188
1189/**
1190 * Function called with the result of our attempt to obtain a name for a given
1191 * public key.
1192 *
1193 * @param cls NULL
1194 * @param zone private key of the zone; NULL on disconnect
1195 * @param label label of the records; NULL on disconnect
1196 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1197 * @param rd array of records with data to store
1198 */
1199static void
1200handle_reverse_lookup (void *cls,
1201 const struct GNUNET_CRYPTO_PrivateKey *zone,
1202 const char *label,
1203 unsigned int rd_count,
1204 const struct GNUNET_GNSRECORD_Data *rd)
1205{
1206 (void) cls;
1207 (void) zone;
1208 (void) rd_count;
1209 (void) rd;
1210 reverse_qe = NULL;
1211 if (NULL == label)
1212 fprintf (stdout, "%s\n", reverse_pkey);
1213 else
1214 fprintf (stdout, "%s.%s\n", label, ego_name);
1215 finish_command ();
1216}
1217
1218
1219/**
1220 * Function called if lookup for deletion fails.
1221 */
1222static void
1223del_lookup_error_cb (void *cls)
1224{
1225 (void) cls;
1226 del_qe = NULL;
1227 GNUNET_break (0);
1228 ret = 1;
1229 finish_command ();
1230}
1231
1232
1233/**
1234 * We were asked to delete something; this function is called with
1235 * the existing records. Now we should determine what should be
1236 * deleted and then issue the deletion operation.
1237 *
1238 * @param cls NULL
1239 * @param zone private key of the zone we are deleting from
1240 * @param label name of the records we are editing
1241 * @param rd_count size of the @a rd array
1242 * @param rd existing records
1243 */
1244static void
1245del_monitor (void *cls,
1246 const struct GNUNET_CRYPTO_PrivateKey *zone,
1247 const char *label,
1248 unsigned int rd_count,
1249 const struct GNUNET_GNSRECORD_Data *rd)
1250{
1251 struct GNUNET_GNSRECORD_Data rdx[rd_count];
1252 unsigned int rd_left;
1253 uint32_t type;
1254 char *vs;
1255
1256 (void) cls;
1257 (void) zone;
1258 del_qe = NULL;
1259 if (0 == rd_count)
1260 {
1261 fprintf (stderr,
1262 _ (
1263 "There are no records under label `%s' that could be deleted.\n"),
1264 label);
1265 ret = 1;
1266 finish_command ();
1267 return;
1268 }
1269 if ((NULL == value) && (NULL == typestring))
1270 {
1271 /* delete everything */
1272 del_qe = GNUNET_NAMESTORE_record_set_store (ns,
1273 &zone_pkey,
1274 name,
1275 0,
1276 NULL,
1277 &del_continuation,
1278 NULL);
1279 return;
1280 }
1281 rd_left = 0;
1282 if (NULL != typestring)
1283 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1284 else
1285 type = GNUNET_GNSRECORD_TYPE_ANY;
1286 for (unsigned int i = 0; i < rd_count; i++)
1287 {
1288 vs = NULL;
1289 if (! (((GNUNET_GNSRECORD_TYPE_ANY == type) ||
1290 (rd[i].record_type == type)) &&
1291 ((NULL == value) ||
1292 (NULL ==
1293 (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1294 rd[i].data,
1295 rd[i].data_size)))) ||
1296 (0 == strcmp (vs, value)))))
1297 rdx[rd_left++] = rd[i];
1298 GNUNET_free (vs);
1299 }
1300 if (rd_count == rd_left)
1301 {
1302 /* nothing got deleted */
1303 fprintf (
1304 stderr,
1305 _ (
1306 "There are no records under label `%s' that match the request for deletion.\n"),
1307 label);
1308 finish_command ();
1309 return;
1310 }
1311 /* delete everything but what we copied to 'rdx' */
1312 del_qe = GNUNET_NAMESTORE_record_set_store (ns,
1313 &zone_pkey,
1314 name,
1315 rd_left,
1316 rdx,
1317 &del_continuation,
1318 NULL);
1319}
1320
1321
1322static void
1323replace_cont (void *cls, enum GNUNET_ErrorCode ec)
1324{
1325 (void) cls;
1326
1327 set_qe = NULL;
1328 if (GNUNET_EC_NONE != ec)
1329 {
1330 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1331 _ ("%s\n"),
1332 GNUNET_ErrorCode_get_hint (ec));
1333 ret = 1; /* fail from 'main' */
1334 }
1335 finish_command ();
1336}
1337
1338
1339/**
1340 * We have obtained the zone's private key, so now process
1341 * the main commands using it.
1342 *
1343 * @param cfg configuration to use
1344 */
1345static void
1346run_with_zone_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg)
1347{
1348 struct GNUNET_GNSRECORD_Data rd;
1349 enum GNUNET_GNSRECORD_Filter filter_flags = GNUNET_GNSRECORD_FILTER_NONE;
1350
1351 if (omit_private)
1352 filter_flags |= GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE;
1353 if (include_maintenance)
1354 filter_flags |= GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE;
1355 if (! (add | del | list | (NULL != nickstring) | (NULL != uri)
1356 | (NULL != reverse_pkey) | (NULL != recordset) | (monitor)
1357 | (purge_orphaned) | (list_orphaned) | (purge_zone)) )
1358 {
1359 /* nothing more to be done */
1360 fprintf (stderr, _ ("No options given\n"));
1361 finish_command ();
1362 return;
1363 }
1364
1365 if (NULL != recordset)
1366 {
1367 /* replace entire record set */
1368 unsigned int rd_count;
1369 struct GNUNET_GNSRECORD_Data *rd;
1370
1371 /* FIXME: We could easily support append and delete with this as well */
1372 if (! add)
1373 {
1374 fprintf (stderr, _ ("Recordlines only work with option `%s'\n"),
1375 "-a");
1376 ret = 1;
1377 finish_command ();
1378 return;
1379 }
1380 if (NULL == name)
1381 {
1382 fprintf (stderr,
1383 _ ("Missing option `%s' for operation `%s'\n"),
1384 "-n",
1385 _ ("name"));
1386 ret = 1;
1387 finish_command ();
1388 return;
1389 }
1390 rd_count = 0;
1391 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1392 rd_count++;
1393 rd = GNUNET_new_array (rd_count, struct GNUNET_GNSRECORD_Data);
1394 rd_count = 0;
1395 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1396 {
1397 rd[rd_count] = e->record;
1398 rd_count++;
1399 }
1400 set_qe = GNUNET_NAMESTORE_record_set_store (ns,
1401 &zone_pkey,
1402 name,
1403 rd_count,
1404 rd,
1405 &replace_cont,
1406 NULL);
1407 GNUNET_free (rd);
1408 return;
1409 }
1410 if (NULL != nickstring)
1411 {
1412 if (0 == strlen (nickstring))
1413 {
1414 fprintf (stderr, _ ("Invalid nick `%s'\n"), nickstring);
1415 ret = 1;
1416 finish_command ();
1417 return;
1418 }
1419 add = 1;
1420 typestring = GNUNET_strdup (GNUNET_GNSRECORD_number_to_typename (
1421 GNUNET_GNSRECORD_TYPE_NICK));
1422 name = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
1423 value = GNUNET_strdup (nickstring);
1424 is_public = 0;
1425 expirationstring = GNUNET_strdup ("never");
1426 GNUNET_free (nickstring);
1427 nickstring = NULL;
1428 }
1429
1430 if (add)
1431 {
1432 if (NULL == ego_name)
1433 {
1434 fprintf (stderr,
1435 _ ("Missing option `%s' for operation `%s'\n"),
1436 "-z",
1437 _ ("add"));
1438 ret = 1;
1439 finish_command ();
1440 return;
1441 }
1442 if (NULL == name)
1443 {
1444 fprintf (stderr,
1445 _ ("Missing option `%s' for operation `%s'\n"),
1446 "-n",
1447 _ ("add"));
1448 ret = 1;
1449 finish_command ();
1450 return;
1451 }
1452 if (NULL == typestring)
1453 {
1454 fprintf (stderr,
1455 _ ("Missing option `%s' for operation `%s'\n"),
1456 "-t",
1457 _ ("add"));
1458 ret = 1;
1459 finish_command ();
1460 return;
1461 }
1462 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1463 if (UINT32_MAX == type)
1464 {
1465 fprintf (stderr, _ ("Unsupported type `%s'\n"), typestring);
1466 ret = 1;
1467 finish_command ();
1468 return;
1469 }
1470 if ((GNUNET_DNSPARSER_TYPE_SRV == type) ||
1471 (GNUNET_DNSPARSER_TYPE_TLSA == type) ||
1472 (GNUNET_DNSPARSER_TYPE_SMIMEA == type) ||
1473 (GNUNET_DNSPARSER_TYPE_OPENPGPKEY == type))
1474 {
1475 fprintf (stderr,
1476 _ (
1477 "For DNS record types `SRV', `TLSA', `SMIMEA' and `OPENPGPKEY'"));
1478 fprintf (stderr, ", please use a `BOX' record instead\n");
1479 ret = 1;
1480 finish_command ();
1481 return;
1482 }
1483 if (NULL == value)
1484 {
1485 fprintf (stderr,
1486 _ ("Missing option `%s' for operation `%s'\n"),
1487 "-V",
1488 _ ("add"));
1489 ret = 1;
1490 finish_command ();
1491 return;
1492 }
1493 if (GNUNET_OK !=
1494 GNUNET_GNSRECORD_string_to_value (type, value, &data, &data_size))
1495 {
1496 fprintf (stderr,
1497 _ ("Value `%s' invalid for record type `%s'\n"),
1498 value,
1499 typestring);
1500 ret = 1;
1501 finish_command ();
1502 return;
1503 }
1504 if (NULL == expirationstring)
1505 {
1506 fprintf (stderr,
1507 _ ("Missing option `%s' for operation `%s'\n"),
1508 "-e",
1509 _ ("add"));
1510 ret = 1;
1511 finish_command ();
1512 return;
1513 }
1514 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1515 {
1516 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1517 ret = 1;
1518 finish_command ();
1519 return;
1520 }
1521 add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1522 &zone_pkey,
1523 name,
1524 &add_error_cb,
1525 NULL,
1526 &get_existing_record,
1527 NULL);
1528 }
1529 if (del)
1530 {
1531 if (NULL == ego_name)
1532 {
1533 fprintf (stderr,
1534 _ ("Missing option `%s' for operation `%s'\n"),
1535 "-z",
1536 _ ("del"));
1537 ret = 1;
1538 finish_command ();
1539 return;
1540 }
1541 if (NULL == name)
1542 {
1543 fprintf (stderr,
1544 _ ("Missing option `%s' for operation `%s'\n"),
1545 "-n",
1546 _ ("del"));
1547 ret = 1;
1548 finish_command ();
1549 return;
1550 }
1551 del_qe = GNUNET_NAMESTORE_records_lookup2 (ns,
1552 &zone_pkey,
1553 name,
1554 &del_lookup_error_cb,
1555 NULL,
1556 &del_monitor,
1557 NULL,
1558 filter_flags);
1559 }
1560 if (purge_orphaned)
1561 {
1562 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1563 NULL,
1564 &zone_iteration_error_cb,
1565 NULL,
1566 &purge_orphans_iterator,
1567 NULL,
1568 &zone_iteration_finished,
1569 NULL,
1570 filter_flags);
1571
1572 }
1573 else if (purge_zone)
1574 {
1575 if (NULL == ego_name)
1576 {
1577 fprintf (stderr,
1578 _ ("Missing option `%s' for operation `%s'\n"),
1579 "-z",
1580 _ ("purge-zone"));
1581 ret = 1;
1582 finish_command ();
1583 return;
1584 }
1585 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1586 &zone_pkey,
1587 &zone_iteration_error_cb,
1588 NULL,
1589 &purge_zone_iterator,
1590 NULL,
1591 &zone_iteration_finished,
1592 NULL,
1593 filter_flags);
1594
1595 }
1596 else if (list || list_orphaned)
1597 {
1598 if (NULL != name)
1599 {
1600 if (NULL == ego_name)
1601 {
1602 fprintf (stderr,
1603 _ ("Missing option `%s' for operation `%s'\n"),
1604 "-z",
1605 _ ("list"));
1606 ret = 1;
1607 finish_command ();
1608 return;
1609 }
1610 get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1611 &zone_pkey,
1612 name,
1613 &lookup_error_cb,
1614 NULL,
1615 &display_record_lookup,
1616 NULL);
1617 }
1618 else
1619 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1620 (NULL == ego_name) ?
1621 NULL : &zone_pkey,
1622 &zone_iteration_error_cb,
1623 NULL,
1624 &display_record_iterator,
1625 NULL,
1626 &zone_iteration_finished,
1627 NULL,
1628 filter_flags);
1629 }
1630 if (NULL != reverse_pkey)
1631 {
1632 struct GNUNET_CRYPTO_PublicKey pubkey;
1633
1634 if (NULL == ego_name)
1635 {
1636 fprintf (stderr,
1637 _ ("Missing option `%s' for operation `%s'\n"),
1638 "-z",
1639 _ ("reverse-pkey"));
1640 ret = 1;
1641 finish_command ();
1642 return;
1643 }
1644 if (GNUNET_OK !=
1645 GNUNET_CRYPTO_public_key_from_string (reverse_pkey,
1646 &pubkey))
1647 {
1648 fprintf (stderr,
1649 _ ("Invalid public key for reverse lookup `%s'\n"),
1650 reverse_pkey);
1651 ret = 1;
1652 finish_command ();
1653 return;
1654 }
1655 reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1656 &zone_pkey,
1657 &pubkey,
1658 &reverse_error_cb,
1659 NULL,
1660 &handle_reverse_lookup,
1661 NULL);
1662 }
1663 if (NULL != uri)
1664 {
1665 char sh[105];
1666 char sname[64];
1667 struct GNUNET_CRYPTO_PublicKey pkey;
1668 if (NULL == ego_name)
1669 {
1670 fprintf (stderr,
1671 _ ("Missing option `%s' for operation `%s'\n"),
1672 "-z",
1673 _ ("uri"));
1674 ret = 1;
1675 finish_command ();
1676 return;
1677 }
1678
1679 memset (sh, 0, 105);
1680 memset (sname, 0, 64);
1681
1682 if ((2 != (sscanf (uri, "gnunet://gns/%58s/%63s", sh, sname))) ||
1683 (GNUNET_OK !=
1684 GNUNET_CRYPTO_public_key_from_string (sh, &pkey)))
1685 {
1686 fprintf (stderr, _ ("Invalid URI `%s'\n"), uri);
1687 ret = 1;
1688 finish_command ();
1689 return;
1690 }
1691 if (NULL == expirationstring)
1692 {
1693 fprintf (stderr,
1694 _ ("Missing option `%s' for operation `%s'\n"),
1695 "-e",
1696 _ ("add"));
1697 ret = 1;
1698 finish_command ();
1699 return;
1700 }
1701 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1702 {
1703 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1704 ret = 1;
1705 finish_command ();
1706 return;
1707 }
1708 memset (&rd, 0, sizeof(rd));
1709 rd.data = &pkey;
1710 rd.data_size = GNUNET_CRYPTO_public_key_get_length (&pkey);
1711 rd.record_type = ntohl (pkey.type);
1712 rd.expiration_time = etime;
1713 if (GNUNET_YES == etime_is_rel)
1714 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1715 if (1 == is_shadow)
1716 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW;
1717 if (1 == is_maintenance)
1718 rd.flags |= GNUNET_GNSRECORD_RF_MAINTENANCE;
1719 add_qe_uri = GNUNET_NAMESTORE_record_set_store (ns,
1720 &zone_pkey,
1721 sname,
1722 1,
1723 &rd,
1724 &add_continuation,
1725 &add_qe_uri);
1726 }
1727 if (monitor)
1728 {
1729 zm = GNUNET_NAMESTORE_zone_monitor_start2 (cfg,
1730 (NULL != ego_name) ?
1731 &zone_pkey : NULL,
1732 GNUNET_YES,
1733 &monitor_error_cb,
1734 NULL,
1735 &display_record_monitor,
1736 NULL,
1737 &sync_cb,
1738 NULL,
1739 filter_flags);
1740 }
1741}
1742
1743
1744#define MAX_LINE_LEN 4086
1745
1746#define MAX_ARGS 20
1747
1748static int
1749get_identity_for_string (const char *str,
1750 struct GNUNET_CRYPTO_PrivateKey *zk)
1751{
1752 const struct GNUNET_CRYPTO_PrivateKey *privkey;
1753 struct GNUNET_CRYPTO_PublicKey pubkey;
1754 struct GNUNET_CRYPTO_PublicKey ego_pubkey;
1755 struct EgoEntry *ego_entry;
1756
1757 if (GNUNET_OK == GNUNET_CRYPTO_public_key_from_string (str,
1758 &pubkey))
1759 {
1760 for (ego_entry = ego_head;
1761 NULL != ego_entry; ego_entry = ego_entry->next)
1762 {
1763 privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1764 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &ego_pubkey);
1765 if (0 == memcmp (&ego_pubkey, &pubkey, sizeof (pubkey)))
1766 {
1767 *zk = *privkey;
1768 return GNUNET_OK;
1769 }
1770 }
1771 }
1772 else
1773 {
1774 for (ego_entry = ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1775 {
1776 /** FIXME: Check for zTLD? **/
1777 if (0 != strcmp (str, ego_entry->identifier))
1778 continue;
1779 *zk = *GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1780 return GNUNET_OK;
1781 }
1782 }
1783 return GNUNET_NO;
1784}
1785
1786
1787static void
1788process_command_stdin ()
1789{
1790 char buf[MAX_LINE_LEN];
1791 static struct GNUNET_CRYPTO_PrivateKey next_zone_key;
1792 static char next_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1793 static int finished = GNUNET_NO;
1794 static int have_next_zonekey = GNUNET_NO;
1795 int zonekey_set = GNUNET_NO;
1796 char *tmp;
1797
1798
1799 if (GNUNET_YES == have_next_zonekey)
1800 {
1801 zone_pkey = next_zone_key;
1802 if (NULL != name)
1803 GNUNET_free (name);
1804 name = GNUNET_strdup (next_name);
1805 zonekey_set = GNUNET_YES;
1806 }
1807 while (NULL != fgets (buf, sizeof (buf), stdin))
1808 {
1809 if (1 >= strlen (buf))
1810 continue;
1811 if (buf[strlen (buf) - 1] == '\n')
1812 buf[strlen (buf) - 1] = '\0';
1813 /**
1814 * Check if this is a new name. If yes, and we have records, store them.
1815 */
1816 if (buf[strlen (buf) - 1] == ':')
1817 {
1818 memset (next_name, 0, sizeof (next_name));
1819 strncpy (next_name, buf, strlen (buf) - 1);
1820 tmp = strchr (next_name, '.');
1821 if (NULL == tmp)
1822 {
1823 fprintf (stderr, "Error parsing name `%s'\n", next_name);
1824 GNUNET_SCHEDULER_shutdown ();
1825 ret = 1;
1826 return;
1827 }
1828 if (GNUNET_OK != get_identity_for_string (tmp + 1, &next_zone_key))
1829 {
1830 fprintf (stderr, "Error parsing zone name `%s'\n", tmp + 1);
1831 ret = 1;
1832 GNUNET_SCHEDULER_shutdown ();
1833 return;
1834 }
1835 *tmp = '\0';
1836 have_next_zonekey = GNUNET_YES;
1837 /* Run a command for the previous record set */
1838 if (NULL != recordset)
1839 {
1840 run_with_zone_pkey (cfg);
1841 return;
1842 }
1843 zone_pkey = next_zone_key;
1844 if (NULL != name)
1845 GNUNET_free (name);
1846 name = GNUNET_strdup (next_name);
1847 zonekey_set = GNUNET_YES;
1848 continue;
1849 }
1850 if (GNUNET_NO == zonekey_set)
1851 {
1852 fprintf (stderr, "Warning, encountered recordline without zone\n");
1853 continue;
1854 }
1855 parse_recordline (buf);
1856 }
1857 if (GNUNET_NO == finished)
1858 {
1859 if (NULL != recordset)
1860 {
1861 if (GNUNET_YES == zonekey_set)
1862 {
1863 run_with_zone_pkey (cfg); /** one last time **/
1864 finished = GNUNET_YES;
1865 return;
1866 }
1867 fprintf (stderr, "Warning, encountered recordline without zone\n");
1868 }
1869 }
1870 GNUNET_SCHEDULER_shutdown ();
1871 return;
1872}
1873
1874
1875/**
1876 * Function called with ALL of the egos known to the
1877 * identity service, used on startup if the user did
1878 * not specify a zone on the command-line.
1879 * Once the iteration is done (@a ego is NULL), we
1880 * ask for the default ego for "namestore".
1881 *
1882 * @param cls a `struct GNUNET_CONFIGURATION_Handle`
1883 * @param ego an ego, NULL for end of iteration
1884 * @param ctx NULL
1885 * @param name name associated with @a ego
1886 */
1887static void
1888id_connect_cb (void *cls,
1889 struct GNUNET_IDENTITY_Ego *ego,
1890 void **ctx,
1891 const char *name)
1892{
1893 struct GNUNET_CRYPTO_PublicKey pk;
1894 struct EgoEntry *ego_entry;
1895
1896 (void) ctx;
1897 (void) name;
1898 if ((NULL != name) && (NULL != ego))
1899 {
1900 ego_entry = GNUNET_new (struct EgoEntry);
1901 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1902 ego_entry->ego = ego;
1903 ego_entry->identifier = GNUNET_strdup (name);
1904 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1905 ego_tail,
1906 ego_entry);
1907 if ((NULL != ego_name) &&
1908 (0 == strcmp (name, ego_name)))
1909 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1910 return;
1911 }
1912 if (NULL != ego)
1913 return;
1914 if (read_from_stdin)
1915 {
1916 process_command_stdin ();
1917 return;
1918 }
1919 run_with_zone_pkey (cfg);
1920}
1921
1922
1923/**
1924 * Main function that will be run.
1925 *
1926 * @param cls closure
1927 * @param args remaining command-line arguments
1928 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1929 * @param cfg configuration
1930 */
1931static void
1932run (void *cls,
1933 char *const *args,
1934 const char *cfgfile,
1935 const struct GNUNET_CONFIGURATION_Handle *_cfg)
1936{
1937 (void) cls;
1938 (void) args;
1939 (void) cfgfile;
1940 cfg = _cfg;
1941 if (NULL != args[0])
1942 GNUNET_log (
1943 GNUNET_ERROR_TYPE_WARNING,
1944 _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
1945 args[0]);
1946
1947 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
1948 ns = GNUNET_NAMESTORE_connect (cfg);
1949 if (NULL == ns)
1950 {
1951 fprintf (stderr, _ ("Failed to connect to namestore\n"));
1952 GNUNET_SCHEDULER_shutdown ();
1953 return;
1954 }
1955 idh = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, (void *) cfg);
1956 if (NULL == idh)
1957 {
1958 ret = -1;
1959 fprintf (stderr, _ ("Cannot connect to identity service\n"));
1960 GNUNET_SCHEDULER_shutdown ();
1961 }
1962}
1963
1964
1965/**
1966 * The main function for gnunet-namestore.
1967 *
1968 * @param argc number of arguments from the command line
1969 * @param argv command line arguments
1970 * @return 0 ok, 1 on error
1971 */
1972int
1973main (int argc, char *const *argv)
1974{
1975 int lret;
1976 struct GNUNET_GETOPT_CommandLineOption options[] =
1977 { GNUNET_GETOPT_option_flag ('a', "add", gettext_noop ("add record"), &add),
1978 GNUNET_GETOPT_option_flag ('d',
1979 "delete",
1980 gettext_noop ("delete record"),
1981 &del),
1982 GNUNET_GETOPT_option_flag ('D',
1983 "display",
1984 gettext_noop ("display records"),
1985 &list),
1986 GNUNET_GETOPT_option_flag ('S',
1987 "from-stdin",
1988 gettext_noop ("read commands from stdin"),
1989 &read_from_stdin),
1990 GNUNET_GETOPT_option_string (
1991 'e',
1992 "expiration",
1993 "TIME",
1994 gettext_noop (
1995 "expiration time for record to use (for adding only), \"never\" is possible"),
1996 &expirationstring),
1997 GNUNET_GETOPT_option_string ('i',
1998 "nick",
1999 "NICKNAME",
2000 gettext_noop (
2001 "set the desired nick name for the zone"),
2002 &nickstring),
2003 GNUNET_GETOPT_option_flag ('m',
2004 "monitor",
2005 gettext_noop (
2006 "monitor changes in the namestore"),
2007 &monitor),
2008 GNUNET_GETOPT_option_string ('n',
2009 "name",
2010 "NAME",
2011 gettext_noop (
2012 "name of the record to add/delete/display"),
2013 &name),
2014 GNUNET_GETOPT_option_flag ('r',
2015 "recordline",
2016 gettext_noop ("Output in recordline format"),
2017 &output_recordline),
2018 GNUNET_GETOPT_option_string ('Z',
2019 "zone-to-name",
2020 "KEY",
2021 gettext_noop (
2022 "determine our name for the given KEY"),
2023 &reverse_pkey),
2024 GNUNET_GETOPT_option_string ('t',
2025 "type",
2026 "TYPE",
2027 gettext_noop (
2028 "type of the record to add/delete/display"),
2029 &typestring),
2030 GNUNET_GETOPT_option_string ('u',
2031 "uri",
2032 "URI",
2033 gettext_noop ("URI to import into our zone"),
2034 &uri),
2035 GNUNET_GETOPT_option_string ('V',
2036 "value",
2037 "VALUE",
2038 gettext_noop (
2039 "value of the record to add/delete"),
2040 &value),
2041 GNUNET_GETOPT_option_flag ('p',
2042 "public",
2043 gettext_noop ("create or list public record"),
2044 &is_public),
2045 GNUNET_GETOPT_option_flag ('o',
2046 "omit-private",
2047 gettext_noop ("omit private records"),
2048 &omit_private),
2049 GNUNET_GETOPT_option_flag ('T',
2050 "include-maintenance",
2051 gettext_noop (
2052 "do not filter maintenance records"),
2053 &include_maintenance),
2054 GNUNET_GETOPT_option_flag ('P',
2055 "purge-orphans",
2056 gettext_noop (
2057 "purge namestore of all orphans"),
2058 &purge_orphaned),
2059 GNUNET_GETOPT_option_flag ('O',
2060 "list-orphans",
2061 gettext_noop (
2062 "show private key for orphaned records for recovery using `gnunet-identity -C -P <key>'. Use in combination with --display"),
2063 &list_orphaned),
2064 GNUNET_GETOPT_option_flag ('X',
2065 "purge-zone-records",
2066 gettext_noop (
2067 "delete all records in specified zone"),
2068 &purge_zone),
2069 GNUNET_GETOPT_option_flag (
2070 's',
2071 "shadow",
2072 gettext_noop (
2073 "create shadow record (only valid if all other records of the same type have expired)"),
2074 &is_shadow),
2075 GNUNET_GETOPT_option_flag (
2076 'M',
2077 "maintenance",
2078 gettext_noop (
2079 "create maintenance record (e.g TOMBSTONEs)"),
2080 &is_maintenance),
2081 GNUNET_GETOPT_option_string ('z',
2082 "zone",
2083 "EGO",
2084 gettext_noop (
2085 "name of the ego controlling the zone"),
2086 &ego_name),
2087 GNUNET_GETOPT_OPTION_END };
2088
2089
2090 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2091 return 2;
2092
2093 is_public = -1;
2094 is_shadow = -1;
2095 is_maintenance = -1;
2096 GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
2097 if (GNUNET_OK !=
2098 (lret = GNUNET_PROGRAM_run (argc,
2099 argv,
2100 "gnunet-namestore",
2101 _ ("GNUnet zone manipulation tool"),
2102 options,
2103 &run,
2104 NULL)))
2105 {
2106 GNUNET_free_nz ((void *) argv);
2107 // FIXME
2108 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
2109 return lret;
2110 }
2111 GNUNET_free_nz ((void *) argv);
2112 // FIXME
2113 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
2114 return ret;
2115}
2116
2117
2118/* end of gnunet-namestore.c */
diff --git a/src/cli/namestore/gnunet-zoneimport.c b/src/cli/namestore/gnunet-zoneimport.c
new file mode 100644
index 000000000..aaed808dd
--- /dev/null
+++ b/src/cli/namestore/gnunet-zoneimport.c
@@ -0,0 +1,1882 @@
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 * @file src/namestore/gnunet-zoneimport.c
22 * @brief import a DNS zone for publication in GNS, incremental
23 * @author Christian Grothoff
24 */
25#include <gnunet_util_lib.h>
26#include <gnunet_gnsrecord_lib.h>
27#include <gnunet_namestore_service.h>
28#include <gnunet_statistics_service.h>
29#include <gnunet_identity_service.h>
30
31
32/**
33 * Maximum number of queries pending at the same time.
34 */
35#define THRESH 100
36
37/**
38 * TIME_THRESH is in usecs. How quickly do we submit fresh queries.
39 * Used as an additional throttle.
40 */
41#define TIME_THRESH 10
42
43/**
44 * How often do we retry a query before giving up for good?
45 */
46#define MAX_RETRIES 5
47
48/**
49 * How many DNS requests do we at most issue in rapid series?
50 */
51#define MAX_SERIES 10
52
53/**
54 * How long do we wait at least between series of requests?
55 */
56#define SERIES_DELAY \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, 10)
58
59/**
60 * How long do DNS records have to last at least after being imported?
61 */
62static struct GNUNET_TIME_Relative minimum_expiration_time;
63
64/**
65 * How many requests do we request from NAMESTORE in one batch
66 * during our initial iteration?
67 */
68#define NS_BATCH_SIZE 1024
69
70/**
71 * Some zones may include authoritative records for other
72 * zones, such as foo.com.uk or bar.com.fr. As for GNS
73 * each dot represents a zone cut, we then need to create a
74 * zone on-the-fly to capture those records properly.
75 */
76struct Zone
77{
78 /**
79 * Kept in a DLL.
80 */
81 struct Zone *next;
82
83 /**
84 * Kept in a DLL.
85 */
86 struct Zone *prev;
87
88 /**
89 * Domain of the zone (i.e. "fr" or "com.fr")
90 */
91 char *domain;
92
93 /**
94 * Private key of the zone.
95 */
96 struct GNUNET_CRYPTO_PrivateKey key;
97};
98
99
100/**
101 * Record for the request to be stored by GNS.
102 */
103struct Record
104{
105 /**
106 * Kept in a DLL.
107 */
108 struct Record *next;
109
110 /**
111 * Kept in a DLL.
112 */
113 struct Record *prev;
114
115 /**
116 * GNS record.
117 */
118 struct GNUNET_GNSRECORD_Data grd;
119};
120
121
122/**
123 * Request we should make. We keep this struct in memory per request,
124 * thus optimizing it is crucial for the overall memory consumption of
125 * the zone importer.
126 */
127struct Request
128{
129 /**
130 * Requests are kept in a heap while waiting to be resolved.
131 */
132 struct GNUNET_CONTAINER_HeapNode *hn;
133
134 /**
135 * Active requests are kept in a DLL.
136 */
137 struct Request *next;
138
139 /**
140 * Active requests are kept in a DLL.
141 */
142 struct Request *prev;
143
144 /**
145 * Head of records that should be published in GNS for
146 * this hostname.
147 */
148 struct Record *rec_head;
149
150 /**
151 * Tail of records that should be published in GNS for
152 * this hostname.
153 */
154 struct Record *rec_tail;
155
156 /**
157 * Socket used to make the request, NULL if not active.
158 */
159 struct GNUNET_DNSSTUB_RequestSocket *rs;
160
161 /**
162 * Hostname we are resolving, allocated at the end of
163 * this struct (optimizing memory consumption by reducing
164 * total number of allocations).
165 */
166 char *hostname;
167
168 /**
169 * Namestore operation pending for this record.
170 */
171 struct GNUNET_NAMESTORE_QueueEntry *qe;
172
173 /**
174 * Zone responsible for this request.
175 */
176 const struct Zone *zone;
177
178 /**
179 * At what time does the (earliest) of the returned records
180 * for this name expire? At this point, we need to re-fetch
181 * the record.
182 */
183 struct GNUNET_TIME_Absolute expires;
184
185 /**
186 * While we are fetching the record, the value is set to the
187 * starting time of the DNS operation. While doing a
188 * NAMESTORE store, again set to the start time of the
189 * NAMESTORE operation.
190 */
191 struct GNUNET_TIME_Absolute op_start_time;
192
193 /**
194 * How often did we issue this query? (And failed, reset
195 * to zero once we were successful.)
196 */
197 unsigned int issue_num;
198
199 /**
200 * random 16-bit DNS query identifier.
201 */
202 uint16_t id;
203};
204
205
206/**
207 * Command-line argument specifying desired size of the hash map with
208 * all of our pending names. Usually, we use an automatically growing
209 * map, but this is only OK up to about a million entries. Above that
210 * number, the user must explicitly specify the size at startup.
211 */
212static unsigned int map_size = 1024;
213
214/**
215 * Handle to the identity service.
216 */
217static struct GNUNET_IDENTITY_Handle *id;
218
219/**
220 * Namestore handle.
221 */
222static struct GNUNET_NAMESTORE_Handle *ns;
223
224/**
225 * Handle to the statistics service.
226 */
227static struct GNUNET_STATISTICS_Handle *stats;
228
229/**
230 * Context for DNS resolution.
231 */
232static struct GNUNET_DNSSTUB_Context *ctx;
233
234/**
235 * The number of DNS queries that are outstanding
236 */
237static unsigned int pending;
238
239/**
240 * The number of NAMESTORE record store operations that are outstanding
241 */
242static unsigned int pending_rs;
243
244/**
245 * Number of lookups we performed overall.
246 */
247static unsigned int lookups;
248
249/**
250 * Number of records we had cached.
251 */
252static unsigned int cached;
253
254/**
255 * How many hostnames did we reject (malformed).
256 */
257static unsigned int rejects;
258
259/**
260 * Number of lookups that failed.
261 */
262static unsigned int failures;
263
264/**
265 * Number of records we found.
266 */
267static unsigned int records;
268
269/**
270 * Number of record sets given to namestore.
271 */
272static unsigned int record_sets;
273
274/**
275 * Heap of all requests to perform, sorted by
276 * the time we should next do the request (i.e. by expires).
277 */
278static struct GNUNET_CONTAINER_Heap *req_heap;
279
280/**
281 * Active requests are kept in a DLL.
282 */
283static struct Request *req_head;
284
285/**
286 * Active requests are kept in a DLL.
287 */
288static struct Request *req_tail;
289
290/**
291 * Main task.
292 */
293static struct GNUNET_SCHEDULER_Task *t;
294
295/**
296 * Hash map of requests for which we may still get a response from
297 * the namestore. Set to NULL once the initial namestore iteration
298 * is done.
299 */
300static struct GNUNET_CONTAINER_MultiHashMap *ns_pending;
301
302/**
303 * Current zone iteration handle.
304 */
305static struct GNUNET_NAMESTORE_ZoneIterator *zone_it;
306
307/**
308 * Head of list of zones we are managing.
309 */
310static struct Zone *zone_head;
311
312/**
313 * Tail of list of zones we are managing.
314 */
315static struct Zone *zone_tail;
316
317/**
318 * After how many more results must #ns_lookup_result_cb() ask
319 * the namestore for more?
320 */
321static uint64_t ns_iterator_trigger_next;
322
323/**
324 * Number of DNS requests counted in latency total.
325 */
326static uint64_t total_dns_latency_cnt;
327
328/**
329 * Sum of DNS latencies observed.
330 */
331static struct GNUNET_TIME_Relative total_dns_latency;
332
333/**
334 * Number of records processed (DNS lookup, no NAMESTORE) in total.
335 */
336static uint64_t total_reg_proc_dns;
337
338/**
339 * Number of records processed (DNS lookup, with NAMESTORE) in total.
340 */
341static uint64_t total_reg_proc_dns_ns;
342
343/**
344 * Start time of the regular processing.
345 */
346static struct GNUNET_TIME_Absolute start_time_reg_proc;
347
348/**
349 * Last time we worked before going idle.
350 */
351static struct GNUNET_TIME_Absolute sleep_time_reg_proc;
352
353/**
354 * Time we slept just waiting for work.
355 */
356static struct GNUNET_TIME_Relative idle_time;
357
358
359/**
360 * Callback for #for_all_records
361 *
362 * @param cls closure
363 * @param rec a DNS record
364 */
365typedef void (*RecordProcessor) (void *cls,
366 const struct GNUNET_DNSPARSER_Record *rec);
367
368
369/**
370 * Call @a rp for each record in @a p, regardless of
371 * what response section it is in.
372 *
373 * @param p packet from DNS
374 * @param rp function to call
375 * @param rp_cls closure for @a rp
376 */
377static void
378for_all_records (const struct GNUNET_DNSPARSER_Packet *p,
379 RecordProcessor rp,
380 void *rp_cls)
381{
382 for (unsigned int i = 0; i < p->num_answers; i++)
383 {
384 struct GNUNET_DNSPARSER_Record *rs = &p->answers[i];
385
386 rp (rp_cls, rs);
387 }
388 for (unsigned int i = 0; i < p->num_authority_records; i++)
389 {
390 struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i];
391
392 rp (rp_cls, rs);
393 }
394 for (unsigned int i = 0; i < p->num_additional_records; i++)
395 {
396 struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i];
397
398 rp (rp_cls, rs);
399 }
400}
401
402
403/**
404 * Return just the label of the hostname in @a req.
405 *
406 * @param req request to process hostname of
407 * @return statically allocated pointer to the label,
408 * overwritten upon the next request!
409 */
410static const char *
411get_label (struct Request *req)
412{
413 static char label[64];
414 const char *dot;
415
416 dot = strchr (req->hostname, (unsigned char) '.');
417 if (NULL == dot)
418 {
419 GNUNET_break (0);
420 return NULL;
421 }
422 if (((size_t) (dot - req->hostname)) >= sizeof(label))
423 {
424 GNUNET_break (0);
425 return NULL;
426 }
427 GNUNET_memcpy (label, req->hostname, dot - req->hostname);
428 label[dot - req->hostname] = '\0';
429 return label;
430}
431
432
433/**
434 * Build DNS query for @a hostname.
435 *
436 * @param hostname host to build query for
437 * @param[out] raw_size number of bytes in the query
438 * @return NULL on error, otherwise pointer to statically (!)
439 * allocated query buffer
440 */
441static void *
442build_dns_query (struct Request *req, size_t *raw_size)
443{
444 static char raw[512];
445 char *rawp;
446 struct GNUNET_DNSPARSER_Packet p;
447 struct GNUNET_DNSPARSER_Query q;
448 int ret;
449
450 q.name = (char *) req->hostname;
451 q.type = GNUNET_DNSPARSER_TYPE_NS;
452 q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
453
454 memset (&p, 0, sizeof(p));
455 p.num_queries = 1;
456 p.queries = &q;
457 p.id = req->id;
458 ret = GNUNET_DNSPARSER_pack (&p, UINT16_MAX, &rawp, raw_size);
459 if (GNUNET_OK != ret)
460 {
461 if (GNUNET_NO == ret)
462 GNUNET_free (rawp);
463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
464 "Failed to pack query for hostname `%s'\n",
465 req->hostname);
466 rejects++;
467 return NULL;
468 }
469 if (*raw_size > sizeof(raw))
470 {
471 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
472 "Failed to pack query for hostname `%s'\n",
473 req->hostname);
474 rejects++;
475 GNUNET_break (0);
476 GNUNET_free (rawp);
477 return NULL;
478 }
479 GNUNET_memcpy (raw, rawp, *raw_size);
480 GNUNET_free (rawp);
481 return raw;
482}
483
484
485/**
486 * Free records associated with @a req.
487 *
488 * @param req request to free records of
489 */
490static void
491free_records (struct Request *req)
492{
493 struct Record *rec;
494
495 /* Free records */
496 while (NULL != (rec = req->rec_head))
497 {
498 GNUNET_CONTAINER_DLL_remove (req->rec_head, req->rec_tail, rec);
499 GNUNET_free (rec);
500 }
501}
502
503
504/**
505 * Free @a req and data structures reachable from it.
506 *
507 * @param req request to free
508 */
509static void
510free_request (struct Request *req)
511{
512 free_records (req);
513 GNUNET_free (req);
514}
515
516
517/**
518 * Process as many requests as possible from the queue.
519 *
520 * @param cls NULL
521 */
522static void
523process_queue (void *cls);
524
525
526/**
527 * Insert @a req into DLL sorted by next fetch time.
528 *
529 * @param req request to insert into #req_heap
530 */
531static void
532insert_sorted (struct Request *req)
533{
534 req->hn =
535 GNUNET_CONTAINER_heap_insert (req_heap, req, req->expires.abs_value_us);
536 if (req == GNUNET_CONTAINER_heap_peek (req_heap))
537 {
538 if (NULL != t)
539 GNUNET_SCHEDULER_cancel (t);
540 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
541 t = GNUNET_SCHEDULER_add_at (req->expires, &process_queue, NULL);
542 }
543}
544
545
546/**
547 * Add record to the GNS record set for @a req.
548 *
549 * @param req the request to expand GNS record set for
550 * @param type type to use
551 * @param expiration_time when should @a rec expire
552 * @param data raw data to store
553 * @param data_len number of bytes in @a data
554 */
555static void
556add_record (struct Request *req,
557 uint32_t type,
558 struct GNUNET_TIME_Absolute expiration_time,
559 const void *data,
560 size_t data_len)
561{
562 struct Record *rec;
563
564 rec = GNUNET_malloc (sizeof(struct Record) + data_len);
565 rec->grd.data = &rec[1];
566 rec->grd.expiration_time = expiration_time.abs_value_us;
567 rec->grd.data_size = data_len;
568 rec->grd.record_type = type;
569 rec->grd.flags = GNUNET_GNSRECORD_RF_NONE;
570 GNUNET_memcpy (&rec[1], data, data_len);
571 GNUNET_CONTAINER_DLL_insert (req->rec_head, req->rec_tail, rec);
572}
573
574
575/**
576 * Closure for #check_for_glue.
577 */
578struct GlueClosure
579{
580 /**
581 * Overall request we are processing.
582 */
583 struct Request *req;
584
585 /**
586 * NS name we are looking for glue for.
587 */
588 const char *ns;
589
590 /**
591 * Set to #GNUNET_YES if glue was found.
592 */
593 int found;
594};
595
596
597/**
598 * Try to find glue records for a given NS record.
599 *
600 * @param cls a `struct GlueClosure *`
601 * @param rec record that may contain glue information
602 */
603static void
604check_for_glue (void *cls, const struct GNUNET_DNSPARSER_Record *rec)
605{
606 struct GlueClosure *gc = cls;
607 char dst[65536];
608 size_t dst_len;
609 size_t off;
610 char ip[INET6_ADDRSTRLEN + 1];
611 socklen_t ip_size = (socklen_t) sizeof(ip);
612 struct GNUNET_TIME_Absolute expiration_time;
613 struct GNUNET_TIME_Relative left;
614
615 if (0 != strcasecmp (rec->name, gc->ns))
616 return;
617 expiration_time = rec->expiration_time;
618 left = GNUNET_TIME_absolute_get_remaining (expiration_time);
619 if (0 == left.rel_value_us)
620 return; /* ignore expired glue records */
621 /* if expiration window is too short, bump it to configured minimum */
622 if (left.rel_value_us < minimum_expiration_time.rel_value_us)
623 expiration_time =
624 GNUNET_TIME_relative_to_absolute (minimum_expiration_time);
625 dst_len = sizeof(dst);
626 off = 0;
627 switch (rec->type)
628 {
629 case GNUNET_DNSPARSER_TYPE_A:
630 if (sizeof(struct in_addr) != rec->data.raw.data_len)
631 {
632 GNUNET_break (0);
633 return;
634 }
635 if (NULL == inet_ntop (AF_INET, rec->data.raw.data, ip, ip_size))
636 {
637 GNUNET_break (0);
638 return;
639 }
640 if ((GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
641 dst_len,
642 &off,
643 gc->req->hostname)) &&
644 (GNUNET_OK ==
645 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, &off, ip)))
646 {
647 add_record (gc->req,
648 GNUNET_GNSRECORD_TYPE_GNS2DNS,
649 expiration_time,
650 dst,
651 off);
652 gc->found = GNUNET_YES;
653 }
654 break;
655
656 case GNUNET_DNSPARSER_TYPE_AAAA:
657 if (sizeof(struct in6_addr) != rec->data.raw.data_len)
658 {
659 GNUNET_break (0);
660 return;
661 }
662 if (NULL == inet_ntop (AF_INET6, rec->data.raw.data, ip, ip_size))
663 {
664 GNUNET_break (0);
665 return;
666 }
667 if ((GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
668 dst_len,
669 &off,
670 gc->req->hostname)) &&
671 (GNUNET_OK ==
672 GNUNET_DNSPARSER_builder_add_name (dst, dst_len, &off, ip)))
673 {
674 add_record (gc->req,
675 GNUNET_GNSRECORD_TYPE_GNS2DNS,
676 expiration_time,
677 dst,
678 off);
679 gc->found = GNUNET_YES;
680 }
681 break;
682
683 case GNUNET_DNSPARSER_TYPE_CNAME:
684 if ((GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
685 dst_len,
686 &off,
687 gc->req->hostname)) &&
688 (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
689 dst_len,
690 &off,
691 rec->data.hostname)))
692 {
693 add_record (gc->req,
694 GNUNET_GNSRECORD_TYPE_GNS2DNS,
695 expiration_time,
696 dst,
697 off);
698 gc->found = GNUNET_YES;
699 }
700 break;
701
702 default:
703 /* useless, do nothing */
704 break;
705 }
706}
707
708
709/**
710 * Closure for #process_record().
711 */
712struct ProcessRecordContext
713{
714 /**
715 * Answer we got back and are currently parsing, or NULL
716 * if not active.
717 */
718 struct GNUNET_DNSPARSER_Packet *p;
719
720 /**
721 * Request we are processing.
722 */
723 struct Request *req;
724};
725
726
727/**
728 * We received @a rec for @a req. Remember the answer.
729 *
730 * @param cls a `struct ProcessRecordContext`
731 * @param rec response
732 */
733static void
734process_record (void *cls, const struct GNUNET_DNSPARSER_Record *rec)
735{
736 struct ProcessRecordContext *prc = cls;
737 struct Request *req = prc->req;
738 char dst[65536];
739 size_t dst_len;
740 size_t off;
741 struct GNUNET_TIME_Absolute expiration_time;
742 struct GNUNET_TIME_Relative left;
743
744 dst_len = sizeof(dst);
745 off = 0;
746 records++;
747 if (0 != strcasecmp (rec->name, req->hostname))
748 {
749 GNUNET_log (
750 GNUNET_ERROR_TYPE_DEBUG,
751 "DNS returned record from zone `%s' of type %u while resolving `%s'\n",
752 rec->name,
753 (unsigned int) rec->type,
754 req->hostname);
755 return; /* does not match hostname, might be glue, but
756 not useful for this pass! */
757 }
758 expiration_time = rec->expiration_time;
759 left = GNUNET_TIME_absolute_get_remaining (expiration_time);
760 if (0 == left.rel_value_us)
761 {
762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763 "DNS returned expired record for `%s'\n",
764 req->hostname);
765 GNUNET_STATISTICS_update (stats,
766 "# expired records obtained from DNS",
767 1,
768 GNUNET_NO);
769 return; /* record expired */
770 }
771
772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
773 "DNS returned record that expires at %s for `%s'\n",
774 GNUNET_STRINGS_absolute_time_to_string (expiration_time),
775 req->hostname);
776 /* if expiration window is too short, bump it to configured minimum */
777 if (left.rel_value_us < minimum_expiration_time.rel_value_us)
778 expiration_time =
779 GNUNET_TIME_relative_to_absolute (minimum_expiration_time);
780 switch (rec->type)
781 {
782 case GNUNET_DNSPARSER_TYPE_NS: {
783 struct GlueClosure gc;
784
785 /* check for glue */
786 gc.req = req;
787 gc.ns = rec->data.hostname;
788 gc.found = GNUNET_NO;
789 for_all_records (prc->p, &check_for_glue, &gc);
790 if ((GNUNET_NO == gc.found) &&
791 (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
792 dst_len,
793 &off,
794 req->hostname)) &&
795 (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
796 dst_len,
797 &off,
798 rec->data.hostname)))
799 {
800 /* FIXME: actually check if this is out-of-bailiwick,
801 and if not request explicit resolution... */
802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803 "Converted OOB (`%s') NS record for `%s'\n",
804 rec->data.hostname,
805 rec->name);
806 add_record (req,
807 GNUNET_GNSRECORD_TYPE_GNS2DNS,
808 expiration_time,
809 dst,
810 off);
811 }
812 else
813 {
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
815 "Converted NS record for `%s' using glue\n",
816 rec->name);
817 }
818 break;
819 }
820
821 case GNUNET_DNSPARSER_TYPE_CNAME:
822 if (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
823 dst_len,
824 &off,
825 rec->data.hostname))
826 {
827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
828 "Converting CNAME (`%s') record for `%s'\n",
829 rec->data.hostname,
830 rec->name);
831 add_record (req, rec->type, expiration_time, dst, off);
832 }
833 break;
834
835 case GNUNET_DNSPARSER_TYPE_DNAME:
836 /* No support for DNAME in GNS yet! FIXME: support later! */
837 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
838 "FIXME: not supported: %s DNAME %s\n",
839 rec->name,
840 rec->data.hostname);
841 break;
842
843 case GNUNET_DNSPARSER_TYPE_MX:
844 if (GNUNET_OK ==
845 GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &off, rec->data.mx))
846 {
847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848 "Converting MX (`%s') record for `%s'\n",
849 rec->data.mx->mxhost,
850 rec->name);
851 add_record (req, rec->type, expiration_time, dst, off);
852 }
853 break;
854
855 case GNUNET_DNSPARSER_TYPE_SOA:
856 if (GNUNET_OK ==
857 GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &off, rec->data.soa))
858 {
859 /* NOTE: GNS does not really use SOAs */
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Converting SOA record for `%s'\n",
862 rec->name);
863 add_record (req, rec->type, expiration_time, dst, off);
864 }
865 break;
866
867 case GNUNET_DNSPARSER_TYPE_SRV:
868 if (GNUNET_OK ==
869 GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &off, rec->data.srv))
870 {
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "Converting SRV record for `%s'\n",
873 rec->name);
874 add_record (req, rec->type, expiration_time, dst, off);
875 }
876 break;
877
878 case GNUNET_DNSPARSER_TYPE_URI:
879 if (GNUNET_OK ==
880 GNUNET_DNSPARSER_builder_add_uri (dst, dst_len, &off, rec->data.uri))
881 {
882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
883 "Converting URI record for `%s'\n",
884 rec->name);
885 add_record (req, rec->type, expiration_time, dst, off);
886 }
887 break;
888
889 case GNUNET_DNSPARSER_TYPE_PTR:
890 if (GNUNET_OK == GNUNET_DNSPARSER_builder_add_name (dst,
891 dst_len,
892 &off,
893 rec->data.hostname))
894 {
895 /* !?: what does a PTR record do in a regular TLD??? */
896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
897 "Converting PTR record for `%s' (weird)\n",
898 rec->name);
899 add_record (req, rec->type, expiration_time, dst, off);
900 }
901 break;
902
903 case GNUNET_DNSPARSER_TYPE_CERT:
904 if (GNUNET_OK ==
905 GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &off, rec->data.cert))
906 {
907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908 "Converting CERT record for `%s'\n",
909 rec->name);
910 add_record (req, rec->type, expiration_time, dst, off);
911 }
912 break;
913
914 /* Rest is 'raw' encoded and just needs to be copied IF
915 the hostname matches the requested name; otherwise we
916 simply cannot use it. */
917 case GNUNET_DNSPARSER_TYPE_A:
918 case GNUNET_DNSPARSER_TYPE_AAAA:
919 case GNUNET_DNSPARSER_TYPE_TXT:
920 default:
921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922 "Converting record of type %u for `%s'\n",
923 (unsigned int) rec->type,
924 rec->name);
925 add_record (req,
926 rec->type,
927 expiration_time,
928 rec->data.raw.data,
929 rec->data.raw.data_len);
930 break;
931 }
932}
933
934
935static void
936store_completed_cb (void *cls, enum GNUNET_ErrorCode ec)
937{
938 static struct GNUNET_TIME_Absolute last;
939 struct Request *req = cls;
940
941 req->qe = NULL;
942 if (GNUNET_EC_NONE != ec)
943 {
944 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
945 "Failed to store zone data for `%s': %s\n",
946 req->hostname,
947 GNUNET_ErrorCode_get_hint (ec));
948 }
949 else
950 {
951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
952 "Stored records under `%s' (%d)\n",
953 req->hostname,
954 ec);
955 }
956 total_reg_proc_dns_ns++; /* finished regular processing */
957 pending_rs--;
958 free_records (req);
959 /* compute NAMESTORE statistics */
960 {
961 static uint64_t total_ns_latency_cnt;
962 static struct GNUNET_TIME_Relative total_ns_latency;
963 struct GNUNET_TIME_Relative ns_latency;
964
965 ns_latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
966 total_ns_latency = GNUNET_TIME_relative_add (total_ns_latency, ns_latency);
967 if (0 == total_ns_latency_cnt)
968 last = GNUNET_TIME_absolute_get ();
969 total_ns_latency_cnt++;
970 if (0 == (total_ns_latency_cnt % 1000))
971 {
972 struct GNUNET_TIME_Relative delta;
973
974 delta = GNUNET_TIME_absolute_get_duration (last);
975 last = GNUNET_TIME_absolute_get ();
976 fprintf (stderr,
977 "Processed 1000 records in %s\n",
978 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
979 GNUNET_STATISTICS_set (stats,
980 "# average NAMESTORE PUT latency (μs)",
981 total_ns_latency.rel_value_us
982 / total_ns_latency_cnt,
983 GNUNET_NO);
984 }
985 }
986 /* compute and publish overall velocity */
987 if (0 == (total_reg_proc_dns_ns % 100))
988 {
989 struct GNUNET_TIME_Relative runtime;
990
991 runtime = GNUNET_TIME_absolute_get_duration (start_time_reg_proc);
992 runtime = GNUNET_TIME_relative_subtract (runtime, idle_time);
993 runtime =
994 GNUNET_TIME_relative_divide (runtime,
995 total_reg_proc_dns + total_reg_proc_dns_ns);
996 GNUNET_STATISTICS_set (stats,
997 "# Regular processing completed without NAMESTORE",
998 total_reg_proc_dns,
999 GNUNET_NO);
1000 GNUNET_STATISTICS_set (stats,
1001 "# Regular processing completed with NAMESTORE PUT",
1002 total_reg_proc_dns_ns,
1003 GNUNET_NO);
1004 GNUNET_STATISTICS_set (stats,
1005 "# average request processing latency (μs)",
1006 runtime.rel_value_us,
1007 GNUNET_NO);
1008 GNUNET_STATISTICS_set (stats,
1009 "# total time spent idle (μs)",
1010 idle_time.rel_value_us,
1011 GNUNET_NO);
1012 }
1013
1014 if (NULL == t)
1015 {
1016 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1017 t = GNUNET_SCHEDULER_add_now (&process_queue, NULL);
1018 }
1019}
1020
1021
1022/**
1023 * Function called with the result of a DNS resolution.
1024 *
1025 * @param cls closure with the `struct Request`
1026 * @param dns dns response, never NULL
1027 * @param dns_len number of bytes in @a dns
1028 */
1029static void
1030process_result (void *cls,
1031 const struct GNUNET_TUN_DnsHeader *dns,
1032 size_t dns_len)
1033{
1034 struct Request *req = cls;
1035 struct Record *rec;
1036 struct GNUNET_DNSPARSER_Packet *p;
1037 unsigned int rd_count;
1038
1039 GNUNET_assert (NULL == req->hn);
1040 if (NULL == dns)
1041 {
1042 /* stub gave up */
1043 GNUNET_CONTAINER_DLL_remove (req_head, req_tail, req);
1044 pending--;
1045 if (NULL == t)
1046 {
1047 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1048 t = GNUNET_SCHEDULER_add_now (&process_queue, NULL);
1049 }
1050 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1051 "Stub gave up on DNS reply for `%s'\n",
1052 req->hostname);
1053 GNUNET_STATISTICS_update (stats, "# DNS lookups timed out", 1, GNUNET_NO);
1054 if (req->issue_num > MAX_RETRIES)
1055 {
1056 failures++;
1057 free_request (req);
1058 GNUNET_STATISTICS_update (stats, "# requests given up on", 1, GNUNET_NO);
1059 return;
1060 }
1061 total_reg_proc_dns++;
1062 req->rs = NULL;
1063 insert_sorted (req);
1064 return;
1065 }
1066 if (req->id != dns->id)
1067 {
1068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1069 "DNS ID did not match request, ignoring reply\n");
1070 GNUNET_STATISTICS_update (stats, "# DNS ID mismatches", 1, GNUNET_NO);
1071 return;
1072 }
1073 GNUNET_CONTAINER_DLL_remove (req_head, req_tail, req);
1074 GNUNET_DNSSTUB_resolve_cancel (req->rs);
1075 req->rs = NULL;
1076 pending--;
1077 p = GNUNET_DNSPARSER_parse ((const char *) dns, dns_len);
1078 if (NULL == p)
1079 {
1080 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1081 "Failed to parse DNS reply for `%s'\n",
1082 req->hostname);
1083 GNUNET_STATISTICS_update (stats, "# DNS parser errors", 1, GNUNET_NO);
1084 if (NULL == t)
1085 {
1086 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1087 t = GNUNET_SCHEDULER_add_now (&process_queue, NULL);
1088 }
1089 if (req->issue_num > MAX_RETRIES)
1090 {
1091 failures++;
1092 free_request (req);
1093 GNUNET_STATISTICS_update (stats, "# requests given up on", 1, GNUNET_NO);
1094 return;
1095 }
1096 insert_sorted (req);
1097 return;
1098 }
1099 /* import new records */
1100 req->issue_num = 0; /* success, reset counter! */
1101 {
1102 struct ProcessRecordContext prc = { .req = req, .p = p };
1103
1104 for_all_records (p, &process_record, &prc);
1105 }
1106 GNUNET_DNSPARSER_free_packet (p);
1107 /* count records found, determine minimum expiration time */
1108 req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
1109 {
1110 struct GNUNET_TIME_Relative dns_latency;
1111
1112 dns_latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
1113 total_dns_latency =
1114 GNUNET_TIME_relative_add (total_dns_latency, dns_latency);
1115 total_dns_latency_cnt++;
1116 if (0 == (total_dns_latency_cnt % 1000))
1117 {
1118 GNUNET_STATISTICS_set (stats,
1119 "# average DNS lookup latency (μs)",
1120 total_dns_latency.rel_value_us
1121 / total_dns_latency_cnt,
1122 GNUNET_NO);
1123 }
1124 }
1125 rd_count = 0;
1126 for (rec = req->rec_head; NULL != rec; rec = rec->next)
1127 {
1128 struct GNUNET_TIME_Absolute at;
1129
1130 at.abs_value_us = rec->grd.expiration_time;
1131 req->expires = GNUNET_TIME_absolute_min (req->expires, at);
1132 rd_count++;
1133 }
1134 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1135 "Obtained %u records for `%s'\n",
1136 rd_count,
1137 req->hostname);
1138 /* Instead of going for SOA, simplified for now to look each
1139 day in case we got an empty response */
1140 if (0 == rd_count)
1141 {
1142 req->expires = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
1143 GNUNET_STATISTICS_update (stats,
1144 "# empty DNS replies (usually NXDOMAIN)",
1145 1,
1146 GNUNET_NO);
1147 }
1148 else
1149 {
1150 record_sets++;
1151 }
1152 /* convert records to namestore import format */
1153 {
1154 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
1155 unsigned int off = 0;
1156
1157 /* convert linked list into array */
1158 for (rec = req->rec_head; NULL != rec; rec = rec->next)
1159 rd[off++] = rec->grd;
1160 pending_rs++;
1161 req->op_start_time = GNUNET_TIME_absolute_get ();
1162 req->qe = GNUNET_NAMESTORE_record_set_store (ns,
1163 &req->zone->key,
1164 get_label (req),
1165 rd_count,
1166 rd,
1167 &store_completed_cb,
1168 req);
1169 GNUNET_assert (NULL != req->qe);
1170 }
1171 insert_sorted (req);
1172}
1173
1174
1175/**
1176 * Process as many requests as possible from the queue.
1177 *
1178 * @param cls NULL
1179 */
1180static void
1181process_queue (void *cls)
1182{
1183 struct Request *req;
1184 unsigned int series;
1185 void *raw;
1186 size_t raw_size;
1187 struct GNUNET_TIME_Relative delay;
1188
1189 (void) cls;
1190 delay = GNUNET_TIME_absolute_get_duration (sleep_time_reg_proc);
1191 idle_time = GNUNET_TIME_relative_add (idle_time, delay);
1192 series = 0;
1193 t = NULL;
1194 while (pending + pending_rs < THRESH)
1195 {
1196 req = GNUNET_CONTAINER_heap_peek (req_heap);
1197 if (NULL == req)
1198 break;
1199 if (NULL != req->qe)
1200 return; /* namestore op still pending */
1201 if (NULL != req->rs)
1202 {
1203 GNUNET_break (0);
1204 return; /* already submitted */
1205 }
1206 if (GNUNET_TIME_absolute_get_remaining (req->expires).rel_value_us > 0)
1207 break;
1208 GNUNET_assert (req == GNUNET_CONTAINER_heap_remove_root (req_heap));
1209 req->hn = NULL;
1210 GNUNET_CONTAINER_DLL_insert (req_head, req_tail, req);
1211 GNUNET_assert (NULL == req->rs);
1212 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1213 "Requesting resolution for `%s'\n",
1214 req->hostname);
1215 raw = build_dns_query (req, &raw_size);
1216 if (NULL == raw)
1217 {
1218 GNUNET_break (0);
1219 free_request (req);
1220 continue;
1221 }
1222 req->op_start_time = GNUNET_TIME_absolute_get ();
1223 req->rs = GNUNET_DNSSTUB_resolve (ctx, raw, raw_size, &process_result, req);
1224 GNUNET_assert (NULL != req->rs);
1225 req->issue_num++;
1226 lookups++;
1227 pending++;
1228 series++;
1229 if (series > MAX_SERIES)
1230 break;
1231 }
1232 if (pending + pending_rs >= THRESH)
1233 {
1234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1235 "Stopped processing queue (%u+%u/%u)]\n",
1236 pending,
1237 pending_rs,
1238 THRESH);
1239 return; /* wait for replies */
1240 }
1241 req = GNUNET_CONTAINER_heap_peek (req_heap);
1242 if (NULL == req)
1243 {
1244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1245 "Stopped processing queue: empty queue\n");
1246 return;
1247 }
1248 if (GNUNET_TIME_absolute_get_remaining (req->expires).rel_value_us > 0)
1249 {
1250 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1251 "Waiting until %s for next record (`%s') to expire\n",
1252 GNUNET_STRINGS_absolute_time_to_string (req->expires),
1253 req->hostname);
1254 if (NULL != t)
1255 GNUNET_SCHEDULER_cancel (t);
1256 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1257 t = GNUNET_SCHEDULER_add_at (req->expires, &process_queue, NULL);
1258 return;
1259 }
1260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Throttling\n");
1261 if (NULL != t)
1262 GNUNET_SCHEDULER_cancel (t);
1263 sleep_time_reg_proc = GNUNET_TIME_absolute_get ();
1264 t = GNUNET_SCHEDULER_add_delayed (SERIES_DELAY, &process_queue, NULL);
1265}
1266
1267
1268/**
1269 * Iterator called during #do_shutdown() to free requests in
1270 * the #ns_pending map.
1271 *
1272 * @param cls NULL
1273 * @param key unused
1274 * @param value the `struct Request` to free
1275 * @return #GNUNET_OK
1276 */
1277static int
1278free_request_it (void *cls, const struct GNUNET_HashCode *key, void *value)
1279{
1280 struct Request *req = value;
1281
1282 (void) cls;
1283 (void) key;
1284 free_request (req);
1285 return GNUNET_OK;
1286}
1287
1288
1289/**
1290 * Clean up and terminate the process.
1291 *
1292 * @param cls NULL
1293 */
1294static void
1295do_shutdown (void *cls)
1296{
1297 struct Request *req;
1298 struct Zone *zone;
1299
1300 (void) cls;
1301 if (NULL != id)
1302 {
1303 GNUNET_IDENTITY_disconnect (id);
1304 id = NULL;
1305 }
1306 if (NULL != t)
1307 {
1308 GNUNET_SCHEDULER_cancel (t);
1309 t = NULL;
1310 }
1311 while (NULL != (req = req_head))
1312 {
1313 GNUNET_CONTAINER_DLL_remove (req_head, req_tail, req);
1314 if (NULL != req->qe)
1315 GNUNET_NAMESTORE_cancel (req->qe);
1316 free_request (req);
1317 }
1318 while (NULL != (req = GNUNET_CONTAINER_heap_remove_root (req_heap)))
1319 {
1320 req->hn = NULL;
1321 if (NULL != req->qe)
1322 GNUNET_NAMESTORE_cancel (req->qe);
1323 free_request (req);
1324 }
1325 if (NULL != zone_it)
1326 {
1327 GNUNET_NAMESTORE_zone_iteration_stop (zone_it);
1328 zone_it = NULL;
1329 }
1330 if (NULL != ns)
1331 {
1332 GNUNET_NAMESTORE_disconnect (ns);
1333 ns = NULL;
1334 }
1335 if (NULL != ctx)
1336 {
1337 GNUNET_DNSSTUB_stop (ctx);
1338 ctx = NULL;
1339 }
1340 if (NULL != req_heap)
1341 {
1342 GNUNET_CONTAINER_heap_destroy (req_heap);
1343 req_heap = NULL;
1344 }
1345 if (NULL != ns_pending)
1346 {
1347 GNUNET_CONTAINER_multihashmap_iterate (ns_pending, &free_request_it, NULL);
1348 GNUNET_CONTAINER_multihashmap_destroy (ns_pending);
1349 ns_pending = NULL;
1350 }
1351 while (NULL != (zone = zone_head))
1352 {
1353 GNUNET_CONTAINER_DLL_remove (zone_head, zone_tail, zone);
1354 GNUNET_free (zone->domain);
1355 GNUNET_free (zone);
1356 }
1357 if (NULL != stats)
1358 {
1359 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1360 stats = NULL;
1361 }
1362}
1363
1364
1365/**
1366 * Iterate over all of the zones we care about and see which records
1367 * we may need to re-fetch when.
1368 *
1369 * @param cls NULL
1370 */
1371static void
1372iterate_zones (void *cls);
1373
1374
1375/**
1376 * Function called if #GNUNET_NAMESTORE_records_lookup() failed.
1377 * Just logs an error.
1378 *
1379 * @param cls a `struct Zone`
1380 */
1381static void
1382ns_lookup_error_cb (void *cls)
1383{
1384 struct Zone *zone = cls;
1385
1386 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1387 "Failed to load data from namestore for zone `%s'\n",
1388 zone->domain);
1389 zone_it = NULL;
1390 ns_iterator_trigger_next = 0;
1391 iterate_zones (NULL);
1392}
1393
1394
1395/**
1396 * Process a record that was stored in the namestore.
1397 *
1398 * @param cls a `struct Zone *`
1399 * @param key private key of the zone
1400 * @param label label of the records
1401 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1402 * @param rd array of records with data to store
1403 */
1404static void
1405ns_lookup_result_cb (void *cls,
1406 const struct GNUNET_CRYPTO_PrivateKey *key,
1407 const char *label,
1408 unsigned int rd_count,
1409 const struct GNUNET_GNSRECORD_Data *rd)
1410{
1411 struct Zone *zone = cls;
1412 struct Request *req;
1413 struct GNUNET_HashCode hc;
1414 char *fqdn;
1415
1416 ns_iterator_trigger_next--;
1417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1418 "Obtained NAMESTORE reply, %llu left in round\n",
1419 (unsigned long long) ns_iterator_trigger_next);
1420 if (0 == ns_iterator_trigger_next)
1421 {
1422 ns_iterator_trigger_next = NS_BATCH_SIZE;
1423 GNUNET_STATISTICS_update (stats,
1424 "# NAMESTORE records requested from cache",
1425 ns_iterator_trigger_next,
1426 GNUNET_NO);
1427 GNUNET_NAMESTORE_zone_iterator_next (zone_it, ns_iterator_trigger_next);
1428 }
1429 GNUNET_asprintf (&fqdn, "%s.%s", label, zone->domain);
1430 GNUNET_CRYPTO_hash (fqdn, strlen (fqdn) + 1, &hc);
1431 GNUNET_free (fqdn);
1432 req = GNUNET_CONTAINER_multihashmap_get (ns_pending, &hc);
1433 if (NULL == req)
1434 {
1435 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1436 "Ignoring record `%s' in zone `%s': not on my list!\n",
1437 label,
1438 zone->domain);
1439 return;
1440 }
1441 GNUNET_assert (GNUNET_OK ==
1442 GNUNET_CONTAINER_multihashmap_remove (ns_pending, &hc, req));
1443 GNUNET_break (0 == GNUNET_memcmp (key, &req->zone->key));
1444 GNUNET_break (0 == strcasecmp (label, get_label (req)));
1445 for (unsigned int i = 0; i < rd_count; i++)
1446 {
1447 struct GNUNET_TIME_Absolute at;
1448
1449 if (0 != (rd->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
1450 {
1451 struct GNUNET_TIME_Relative rel;
1452
1453 rel.rel_value_us = rd->expiration_time;
1454 at = GNUNET_TIME_relative_to_absolute (rel);
1455 }
1456 else
1457 {
1458 at.abs_value_us = rd->expiration_time;
1459 }
1460 add_record (req, rd->record_type, at, rd->data, rd->data_size);
1461 }
1462 if (0 == rd_count)
1463 {
1464 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1465 "Empty record set in namestore for `%s'\n",
1466 req->hostname);
1467 }
1468 else
1469 {
1470 unsigned int pos = 0;
1471
1472 cached++;
1473 req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
1474 for (struct Record *rec = req->rec_head; NULL != rec; rec = rec->next)
1475 {
1476 struct GNUNET_TIME_Absolute at;
1477
1478 at.abs_value_us = rec->grd.expiration_time;
1479 req->expires = GNUNET_TIME_absolute_min (req->expires, at);
1480 pos++;
1481 }
1482 if (0 == pos)
1483 req->expires = GNUNET_TIME_UNIT_ZERO_ABS;
1484 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1485 "Hot-start with %u existing records for `%s'\n",
1486 pos,
1487 req->hostname);
1488 }
1489 free_records (req);
1490
1491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1492 "Adding `%s' to worklist to start at %s\n",
1493 req->hostname,
1494 GNUNET_STRINGS_absolute_time_to_string (req->expires));
1495 insert_sorted (req);
1496}
1497
1498
1499/**
1500 * Add @a hostname to the list of requests to be made.
1501 *
1502 * @param hostname name to resolve
1503 */
1504static void
1505queue (const char *hostname)
1506{
1507 struct Request *req;
1508 const char *dot;
1509 struct Zone *zone;
1510 size_t hlen;
1511 struct GNUNET_HashCode hc;
1512
1513 if (GNUNET_OK != GNUNET_DNSPARSER_check_name (hostname))
1514 {
1515 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1516 "Refusing invalid hostname `%s'\n",
1517 hostname);
1518 rejects++;
1519 return;
1520 }
1521 dot = strchr (hostname, (unsigned char) '.');
1522 if (NULL == dot)
1523 {
1524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1525 "Refusing invalid hostname `%s' (lacks '.')\n",
1526 hostname);
1527 rejects++;
1528 return;
1529 }
1530 for (zone = zone_head; NULL != zone; zone = zone->next)
1531 if (0 == strcmp (zone->domain, dot + 1))
1532 break;
1533 if (NULL == zone)
1534 {
1535 rejects++;
1536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1537 "Domain name `%s' not in ego list!\n",
1538 dot + 1);
1539 return;
1540 }
1541
1542 hlen = strlen (hostname) + 1;
1543 req = GNUNET_malloc (sizeof(struct Request) + hlen);
1544 req->zone = zone;
1545 req->hostname = (char *) &req[1];
1546 GNUNET_memcpy (req->hostname, hostname, hlen);
1547 req->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1548 UINT16_MAX);
1549 GNUNET_CRYPTO_hash (req->hostname, hlen, &hc);
1550 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
1551 ns_pending,
1552 &hc,
1553 req,
1554 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1555 {
1556 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1557 "Duplicate hostname `%s' ignored\n",
1558 hostname);
1559 GNUNET_free (req);
1560 return;
1561 }
1562}
1563
1564
1565/**
1566 * We have completed the initial iteration over the namestore's database.
1567 * This function is called on each of the remaining records in
1568 * #move_to_queue to #queue() them, as we will simply not find existing
1569 * records for them any longer.
1570 *
1571 * @param cls NULL
1572 * @param key unused
1573 * @param value a `struct Request`
1574 * @return #GNUNET_OK (continue to iterate)
1575 */
1576static int
1577move_to_queue (void *cls, const struct GNUNET_HashCode *key, void *value)
1578{
1579 struct Request *req = value;
1580
1581 (void) cls;
1582 (void) key;
1583 insert_sorted (req);
1584 return GNUNET_OK;
1585}
1586
1587
1588/**
1589 * Iterate over all of the zones we care about and see which records
1590 * we may need to re-fetch when.
1591 *
1592 * @param cls NULL
1593 */
1594static void
1595iterate_zones (void *cls)
1596{
1597 static struct Zone *last;
1598
1599 (void) cls;
1600 if (NULL != zone_it)
1601 {
1602 zone_it = NULL;
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "Finished iteration over zone `%s'!\n",
1605 last->domain);
1606 /* subtract left-overs from previous iteration */
1607 GNUNET_STATISTICS_update (stats,
1608 "# NAMESTORE records requested from cache",
1609 (long long) (-ns_iterator_trigger_next),
1610 GNUNET_NO);
1611 ns_iterator_trigger_next = 0;
1612 }
1613 GNUNET_assert (NULL != zone_tail);
1614 if (zone_tail == last)
1615 {
1616 /* Done iterating over relevant zones in NAMESTORE, move
1617 rest of hash map to work queue as well. */
1618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1619 "Finished all NAMESTORE iterations!\n");
1620 GNUNET_STATISTICS_set (stats,
1621 "# Domain names without cached reply",
1622 GNUNET_CONTAINER_multihashmap_size (ns_pending),
1623 GNUNET_NO);
1624 GNUNET_CONTAINER_multihashmap_iterate (ns_pending, &move_to_queue, NULL);
1625 GNUNET_CONTAINER_multihashmap_destroy (ns_pending);
1626 ns_pending = NULL;
1627 start_time_reg_proc = GNUNET_TIME_absolute_get ();
1628 total_reg_proc_dns = 0;
1629 total_reg_proc_dns_ns = 0;
1630 return;
1631 }
1632 if (NULL == last)
1633 last = zone_head;
1634 else
1635 last = last->next;
1636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1637 "Starting iteration over zone `%s'!\n",
1638 last->domain);
1639 /* subtract left-overs from previous iteration */
1640 GNUNET_STATISTICS_update (stats,
1641 "# NAMESTORE records requested from cache",
1642 1,
1643 GNUNET_NO);
1644 ns_iterator_trigger_next = 1;
1645 GNUNET_STATISTICS_update (stats, "# zones iterated", 1, GNUNET_NO);
1646 zone_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1647 &last->key,
1648 &ns_lookup_error_cb,
1649 NULL,
1650 &ns_lookup_result_cb,
1651 last,
1652 &iterate_zones,
1653 NULL);
1654}
1655
1656
1657/**
1658 * Begin processing hostnames from stdin.
1659 *
1660 * @param cls NULL
1661 */
1662static void
1663process_stdin (void *cls)
1664{
1665 static struct GNUNET_TIME_Absolute last;
1666 static uint64_t idot;
1667 char hn[256];
1668
1669 (void) cls;
1670 t = NULL;
1671 if (NULL != id)
1672 {
1673 GNUNET_IDENTITY_disconnect (id);
1674 id = NULL;
1675 }
1676 while (NULL != fgets (hn, sizeof(hn), stdin))
1677 {
1678 if (strlen (hn) > 0)
1679 hn[strlen (hn) - 1] = '\0'; /* eat newline */
1680 if (0 == idot)
1681 last = GNUNET_TIME_absolute_get ();
1682 idot++;
1683 if (0 == idot % 100000)
1684 {
1685 struct GNUNET_TIME_Relative delta;
1686
1687 delta = GNUNET_TIME_absolute_get_duration (last);
1688 last = GNUNET_TIME_absolute_get ();
1689 fprintf (stderr,
1690 "Read 100000 domain names in %s\n",
1691 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES));
1692 GNUNET_STATISTICS_set (stats, "# domain names provided", idot, GNUNET_NO);
1693 }
1694 queue (hn);
1695 }
1696 fprintf (stderr,
1697 "Done reading %llu domain names\n",
1698 (unsigned long long) idot);
1699 GNUNET_STATISTICS_set (stats, "# domain names provided", idot, GNUNET_NO);
1700 iterate_zones (NULL);
1701}
1702
1703
1704/**
1705 * Method called to inform about the egos of this peer.
1706 *
1707 * When used with #GNUNET_IDENTITY_connect, this function is
1708 * initially called for all egos and then again whenever a
1709 * ego's name changes or if it is deleted. At the end of
1710 * the initial pass over all egos, the function is once called
1711 * with 'NULL' for @a ego. That does NOT mean that the callback won't
1712 * be invoked in the future or that there was an error.
1713 *
1714 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get, this
1715 * function is only called ONCE, and 'NULL' being passed in @a ego does
1716 * indicate an error (for example because name is taken or no default value is
1717 * known). If @a ego is non-NULL and if '*ctx' is set in those callbacks, the
1718 * value WILL be passed to a subsequent call to the identity callback of
1719 * #GNUNET_IDENTITY_connect (if that one was not NULL).
1720 *
1721 * When an identity is renamed, this function is called with the
1722 * (known) @a ego but the NEW @a name.
1723 *
1724 * When an identity is deleted, this function is called with the
1725 * (known) ego and "NULL" for the @a name. In this case,
1726 * the @a ego is henceforth invalid (and the @a ctx should also be
1727 * cleaned up).
1728 *
1729 * @param cls closure
1730 * @param ego ego handle, NULL for end of list
1731 * @param ctx context for application to store data for this ego
1732 * (during the lifetime of this process, initially NULL)
1733 * @param name name assigned by the user for this ego,
1734 * NULL if the user just deleted the ego and it
1735 * must thus no longer be used
1736 */
1737static void
1738identity_cb (void *cls,
1739 struct GNUNET_IDENTITY_Ego *ego,
1740 void **ctx,
1741 const char *name)
1742{
1743 (void) cls;
1744 (void) ctx;
1745
1746 if (NULL == ego)
1747 {
1748 /* end of iteration */
1749 if (NULL == zone_head)
1750 {
1751 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No zone found\n");
1752 GNUNET_SCHEDULER_shutdown ();
1753 return;
1754 }
1755 /* zone_head non-null, process hostnames from stdin */
1756 t = GNUNET_SCHEDULER_add_now (&process_stdin, NULL);
1757 return;
1758 }
1759 if (NULL != name)
1760 {
1761 struct Zone *zone;
1762
1763 zone = GNUNET_new (struct Zone);
1764 zone->key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1765 zone->domain = GNUNET_strdup (name);
1766 GNUNET_CONTAINER_DLL_insert (zone_head, zone_tail, zone);
1767 }
1768}
1769
1770
1771/**
1772 * Process requests from the queue, then if the queue is
1773 * not empty, try again.
1774 *
1775 * @param cls NULL
1776 * @param args remaining command-line arguments
1777 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1778 * @param cfg configuration
1779 */
1780static void
1781run (void *cls,
1782 char *const *args,
1783 const char *cfgfile,
1784 const struct GNUNET_CONFIGURATION_Handle *cfg)
1785{
1786 (void) cls;
1787 (void) args;
1788 (void) cfgfile;
1789 stats = GNUNET_STATISTICS_create ("zoneimport", cfg);
1790 req_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1791 ns_pending = GNUNET_CONTAINER_multihashmap_create (map_size, GNUNET_NO);
1792 if (NULL == ns_pending)
1793 {
1794 fprintf (stderr, "Failed to allocate memory for main hash map\n");
1795 return;
1796 }
1797 ctx = GNUNET_DNSSTUB_start (256);
1798 if (NULL == ctx)
1799 {
1800 fprintf (stderr, "Failed to initialize GNUnet DNS STUB\n");
1801 return;
1802 }
1803 if (NULL == args[0])
1804 {
1805 fprintf (stderr,
1806 "You must provide a list of DNS resolvers on the command line\n");
1807 return;
1808 }
1809 for (unsigned int i = 0; NULL != args[i]; i++)
1810 {
1811 if (GNUNET_OK != GNUNET_DNSSTUB_add_dns_ip (ctx, args[i]))
1812 {
1813 fprintf (stderr, "Failed to use `%s' for DNS resolver\n", args[i]);
1814 return;
1815 }
1816 }
1817
1818
1819 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1820 ns = GNUNET_NAMESTORE_connect (cfg);
1821 if (NULL == ns)
1822 {
1823 GNUNET_SCHEDULER_shutdown ();
1824 return;
1825 }
1826 id = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL);
1827}
1828
1829
1830/**
1831 * Call with IP address of resolver to query.
1832 *
1833 * @param argc should be 2
1834 * @param argv[1] should contain IP address
1835 * @return 0 on success
1836 */
1837int
1838main (int argc, char *const *argv)
1839{
1840 struct GNUNET_GETOPT_CommandLineOption options[] =
1841 { GNUNET_GETOPT_option_uint ('s',
1842 "size",
1843 "MAPSIZE",
1844 gettext_noop (
1845 "size to use for the main hash map"),
1846 &map_size),
1847 GNUNET_GETOPT_option_relative_time (
1848 'm',
1849 "minimum-expiration",
1850 "RELATIVETIME",
1851 gettext_noop ("minimum expiration time we assume for imported records"),
1852 &minimum_expiration_time),
1853 GNUNET_GETOPT_OPTION_END };
1854 int ret;
1855
1856 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1857 return 2;
1858 if (GNUNET_OK != (ret = GNUNET_PROGRAM_run (argc,
1859 argv,
1860 "gnunet-zoneimport",
1861 "import DNS zone into namestore",
1862 options,
1863 &run,
1864 NULL)))
1865 return ret;
1866 GNUNET_free_nz ((void *) argv);
1867 fprintf (stderr,
1868 "Rejected %u names, had %u cached, did %u lookups, stored %u record sets\n"
1869 "Found %u records, %u lookups failed, %u/%u pending on shutdown\n",
1870 rejects,
1871 cached,
1872 lookups,
1873 record_sets,
1874 records,
1875 failures,
1876 pending,
1877 pending_rs);
1878 return 0;
1879}
1880
1881
1882/* end of gnunet-zoneimport.c */
diff --git a/src/cli/namestore/meson.build b/src/cli/namestore/meson.build
new file mode 100644
index 000000000..e619876c5
--- /dev/null
+++ b/src/cli/namestore/meson.build
@@ -0,0 +1,38 @@
1executable ('gnunet-namestore',
2 ['gnunet-namestore.c'],
3 dependencies: [libgnunetnamestore_dep,
4 libgnunetutil_dep,
5 libgnunetgnsrecord_dep,
6 libgnunetidentity_dep],
7 include_directories: [incdir, configuration_inc],
8 install: true,
9 install_dir: get_option('bindir'))
10executable ('gnunet-namestore-dbtool',
11 ['gnunet-namestore-dbtool.c'],
12 dependencies: [libgnunetnamestore_dep,
13 libgnunetutil_dep,
14 libgnunetgnsrecord_dep,
15 libgnunetidentity_dep],
16 include_directories: [incdir, configuration_inc],
17 install: true,
18 install_dir: get_option('bindir'))
19executable ('gnunet-namestore-zonefile',
20 ['gnunet-namestore-zonefile.c'],
21 dependencies: [libgnunetnamestore_dep,
22 libgnunetutil_dep,
23 libgnunetgnsrecord_dep,
24 libgnunetidentity_dep],
25 include_directories: [incdir, configuration_inc],
26 install: true,
27 install_dir: get_option('bindir'))
28executable ('gnunet-zoneimport',
29 ['gnunet-zoneimport.c'],
30 dependencies: [libgnunetnamestore_dep,
31 libgnunetutil_dep,
32 libgnunetstatistics_dep,
33 libgnunetgnsrecord_dep,
34 libgnunetidentity_dep],
35 include_directories: [incdir, configuration_inc],
36 install: true,
37 install_dir: get_option('bindir'))
38
diff --git a/src/cli/namestore/test_namestore_box_lightest.sh b/src/cli/namestore/test_namestore_box_lightest.sh
new file mode 100755
index 000000000..3c8ad2799
--- /dev/null
+++ b/src/cli/namestore/test_namestore_box_lightest.sh
@@ -0,0 +1,63 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_RECORD_NAME_DNS="trust"
19TEST_RECORD_VALUE_SMIMEA="49152 49153 53 0 0 1 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971"
20TEST_RECORD_VALUE_URI="49152 49152 256 10 10 \"http://lightest.nletlabs.nl/\""
21which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
22
23function start_peer
24{
25 gnunet-arm -s -c $CONFIGURATION
26 gnunet-identity -C testego -c $CONFIGURATION
27}
28
29function stop_peer
30{
31 gnunet-identity -D testego -c $CONFIGURATION
32 gnunet-arm -e -c $CONFIGURATION
33}
34
35
36start_peer
37# Create a public SMIMEA record
38gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t BOX -V "$TEST_RECORD_VALUE_SMIMEA" -e never -c $CONFIGURATION
39NAMESTORE_RES=$?
40
41if [ $NAMESTORE_RES = 0 ]
42then
43 echo "PASS: Creating boxed name in namestore SMIMEA"
44else
45 echo "FAIL: Creating boxed name in namestore failed with $NAMESTORE_RES."
46 stop_peer
47 exit 1
48fi
49
50# Create a public URI record
51gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t BOX -V "$TEST_RECORD_VALUE_URI" -e never -c $CONFIGURATION
52NAMESTORE_RES=$?
53
54if [ $NAMESTORE_RES = 0 ]
55then
56 echo "PASS: Creating boxed name in namestore URI"
57else
58 echo "FAIL: Creating boxed name in namestore failed with $NAMESTORE_RES."
59 stop_peer
60 exit 1
61fi
62
63stop_peer \ No newline at end of file
diff --git a/src/cli/namestore/test_namestore_delete.sh b/src/cli/namestore/test_namestore_delete.sh
new file mode 100755
index 000000000..b861a4bc0
--- /dev/null
+++ b/src/cli/namestore/test_namestore_delete.sh
@@ -0,0 +1,68 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_DOMAIN_PLUS="www.gnu"
19TEST_DOMAIN_DNS="www3.gnu"
20TEST_IP_PLUS="127.0.0.1"
21TEST_IP_DNS="131.159.74.67"
22TEST_RECORD_CNAME_SERVER="server"
23TEST_RECORD_CNAME_PLUS="server.+"
24TEST_RECORD_CNAME_DNS="gnunet.org"
25TEST_RECORD_NAME_SERVER="server"
26TEST_RECORD_NAME_PLUS="www"
27TEST_RECORD_NAME_DNS="www3"
28which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
29
30function start_peer
31{
32 gnunet-arm -s -c $CONFIGURATION
33 gnunet-identity -C testego -c $CONFIGURATION
34}
35
36function stop_peer
37{
38 gnunet-identity -D testego -c $CONFIGURATION
39 gnunet-arm -e -c $CONFIGURATION
40}
41
42
43start_peer
44# Create a public record
45gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
46# Delete record
47gnunet-namestore -p -z testego -d -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
48# List all records
49OUTPUT=`gnunet-namestore -p -z testego -D`
50FOUND_IP=false
51FOUND_NAME=false
52for LINE in $OUTPUT ;
53 do
54 if echo "$LINE" | grep -q "$TEST_RECORD_NAME_DNS"; then
55 FOUND_NAME=true;
56 fi
57 if echo "$LINE" | grep -q "$TEST_IP_PLUS"; then
58 FOUND_IP=true;
59 fi
60 done
61stop_peer
62
63
64if [ $FOUND_IP = true ]
65then
66 echo "FAIL: Delete name in namestore: IP returned"
67 exit 1
68fi
diff --git a/src/cli/namestore/test_namestore_lookup.sh b/src/cli/namestore/test_namestore_lookup.sh
new file mode 100755
index 000000000..1c96e102a
--- /dev/null
+++ b/src/cli/namestore/test_namestore_lookup.sh
@@ -0,0 +1,63 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_IP_PLUS="127.0.0.1"
19TEST_RECORD_NAME_DNS="www3"
20which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
21
22# start peer
23gnunet-arm -s -c $CONFIGURATION
24gnunet-identity -C testego -c $CONFIGURATION
25
26# Create a public record
27gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
28NAMESTORE_RES=$?
29# Lookup specific name
30OUTPUT=`gnunet-namestore -p -z testego -n $TEST_RECORD_NAME_DNS -D`
31
32
33FOUND_IP=false
34FOUND_NAME=false
35for LINE in $OUTPUT ;
36 do
37 if echo "$LINE" | grep -q "$TEST_RECORD_NAME_DNS"; then
38 FOUND_NAME=true;
39 #echo $FOUND_NAME
40 fi
41 if echo "$LINE" | grep -q "$TEST_IP_PLUS"; then
42 FOUND_IP=true;
43 #echo $FOUND_IP
44 fi
45done
46# stop peer
47gnunet-identity -D testego -c $CONFIGURATION
48gnunet-arm -e -c $CONFIGURATION
49
50
51if [ $FOUND_NAME = true -a $FOUND_IP = true ]
52then
53 echo "PASS: Lookup name in namestore"
54 exit 0
55elif [ $FOUND_NAME = false ]
56then
57 echo "FAIL: Lookup name in namestore: name not returned"
58 exit 1
59elif [ $FOUND_IP = false ]
60then
61 echo "FAIL: Lookup name in namestore: IP not returned"
62 exit 1
63fi
diff --git a/src/cli/namestore/test_namestore_put.sh b/src/cli/namestore/test_namestore_put.sh
new file mode 100755
index 000000000..eaf7d44b4
--- /dev/null
+++ b/src/cli/namestore/test_namestore_put.sh
@@ -0,0 +1,55 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_DOMAIN_PLUS="www.gnu"
19TEST_DOMAIN_DNS="www3.gnu"
20TEST_IP_PLUS="127.0.0.1"
21TEST_IP_DNS="131.159.74.67"
22TEST_RECORD_CNAME_SERVER="server"
23TEST_RECORD_CNAME_PLUS="server.+"
24TEST_RECORD_CNAME_DNS="gnunet.org"
25TEST_RECORD_NAME_SERVER="server"
26TEST_RECORD_NAME_PLUS="www"
27TEST_RECORD_NAME_DNS="www3"
28which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
29
30function start_peer
31{
32 gnunet-arm -s -c $CONFIGURATION
33 gnunet-identity -C testego -c $CONFIGURATION
34}
35
36function stop_peer
37{
38 gnunet-identity -D testego -c $CONFIGURATION
39 gnunet-arm -e -c $CONFIGURATION
40}
41
42
43start_peer
44# Create a public record
45gnunet-namestore -p -z testego -a -n $TEST_RECORD_NAME_DNS -t A -V $TEST_IP_PLUS -e never -c $CONFIGURATION
46NAMESTORE_RES=$?
47stop_peer
48
49if [ $NAMESTORE_RES = 0 ]
50then
51 echo "PASS: Creating name in namestore"
52else
53 echo "FAIL: Creating name in namestore failed with $NAMESTORE_RES."
54 exit 1
55fi
diff --git a/src/cli/namestore/test_namestore_put_multiple.sh b/src/cli/namestore/test_namestore_put_multiple.sh
new file mode 100755
index 000000000..4c7340440
--- /dev/null
+++ b/src/cli/namestore/test_namestore_put_multiple.sh
@@ -0,0 +1,112 @@
1#!/bin/bash
2
3# Check for required packages
4if ! [ -x "$(command -v gnunet-namestore)" ]; then
5 echo 'bind/named is not installed' >&2
6 exit 1
7fi
8
9# Check if gnunet is running
10gnunet-arm -I 2&>1 /dev/null
11ret=$?
12if [ 0 -ne $ret ]; then
13 echo 'gnunet services are not running'
14 exit 1
15fi
16
17## GNUNET part
18# Check if identity exists and deletes and readds it to get rid of entries in zone
19gnunet-identity -d | grep randomtestingid 2>&1 /dev/null
20ret=$?
21
22if [ 0 -ne $ret ]; then
23 gnunet-identity -D randomtestingid
24 gnunet-identity -C randomtestingid
25fi
26
27function get_record_type {
28 arr=$1
29 typ=$(echo -n "${arr[0]}" | cut -d' ' -f1)
30 echo "$typ"
31}
32
33function get_value {
34 arr=$1
35 val=$(echo -n "${arr[0]}" | cut -d' ' -f4-)
36 echo "$val"
37}
38
39function testing {
40 label=$1
41 records=$2
42 recordstring=""
43 typ=$(get_record_type "${records[@]}")
44 for i in "${records[@]}"
45 do
46 recordstring+="$i"$'\n'
47 done
48 echo "$recordstring"
49 gnunet-namestore -a -S <<EOF
50$label.randomtestingid:
51 $recordstring
52EOF
53 ret=$?
54 if [ 0 -ne $ret ]; then
55 echo "failed to add record $label: $recordstring"
56 fi
57 gnunet-gns -t "$typ" -u foo2.randomtestingid 2>&1 /dev/null
58 if [ 0 -ne $ret ]; then
59 echo "record $label could not be found"
60 fi
61}
62
63# TEST CASES
64# 1
65echo "Testing adding of single A record with -R"
66declare -a arr=('A 1200 [r] 127.0.0.1')
67testing test1 "${arr[@]}"
68# 2
69echo "Testing adding of multiple A records with -R"
70declare -a arr=('A 1200 [r] 127.0.0.1' 'A 2400 [r] 127.0.0.2')
71testing test2 "${arr[@]}"
72# 3
73echo "Testing adding of multiple different records with -R"
74declare -a arr=('A 1200 [r] 127.0.0.1' 'AAAA 2400 [r] 2002::')
75testing test3 "${arr[@]}"
76# 4
77echo "Testing adding of single GNS2DNS record with -R"
78declare -a arr=('GNS2DNS 86400 [r] gnu.org@127.0.0.1')
79testing test4 "${arr[@]}"
80# 5
81echo "Testing adding of single GNS2DNS shadow record with -R"
82declare -a arr=('GNS2DNS 86409 [rs] gnu.org@127.0.0.250')
83testing test5 "${arr[@]}"
84# 6
85echo "Testing adding of multiple GNS2DNS record with -R"
86declare -a arr=('GNS2DNS 1 [r] gnunet.org@127.0.0.1' 'GNS2DNS 3600 [s] gnunet.org@127.0.0.2')
87testing test6 "${arr[@]}"
88val=$(gnunet-gns -t GNS2DNS -u test6.randomtestingid)
89if [[ $val == *"127.0.0.1"* ]]; then
90 echo "shadow!"
91fi
92echo "Sleeping to let record expire"
93sleep 5
94val=$(gnunet-gns -t GNS2DNS -u test6.randomtestingid)
95if [[ $val == *"127.0.0.2"* ]]; then
96 echo "no shadow!"
97fi
98# 7
99echo "Testing adding MX record with -R"
100declare -a arr=('MX 3600 [r] 10,mail')
101testing test7 "${arr[@]}"
102# 8
103echo "Testing adding TXT record with -R"
104declare -a arr=('TXT 3600 [r] Pretty_Unicorns')
105testing test8 "${arr[@]}"
106# 8
107#echo "Testing adding TXT record with -R"
108#declare -a arr=('SRV 3600 [r] _autodiscover_old._tcp.bfh.ch.')
109#testing test8 "${arr[@]}"
110
111# CLEANUP
112gnunet-identity -D randomtestingid
diff --git a/src/cli/namestore/test_namestore_put_stdin.sh b/src/cli/namestore/test_namestore_put_stdin.sh
new file mode 100755
index 000000000..deb7bc4cb
--- /dev/null
+++ b/src/cli/namestore/test_namestore_put_stdin.sh
@@ -0,0 +1,68 @@
1#!/bin/bash
2CONFIGURATION="test_namestore_api.conf"
3trap "gnunet-arm -e -c $CONFIGURATION" SIGINT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `$LOCATION -c $CONFIGURATION -s PATHS -o GNUNET_HOME`
18TEST_RECORD_NAME="www3"
19TEST_RECORD_NAME2="www"
20TEST_IP="8.7.6.5"
21TEST_IP2="1.2.3.4"
22
23which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
24
25function start_peer
26{
27 gnunet-arm -s -c $CONFIGURATION
28 gnunet-identity -C testego -c $CONFIGURATION
29 gnunet-identity -C testego2 -c $CONFIGURATION
30}
31
32function stop_peer
33{
34 gnunet-identity -D testego -c $CONFIGURATION
35 gnunet-identity -D testego2 -c $CONFIGURATION
36 gnunet-arm -e -c $CONFIGURATION
37}
38
39
40start_peer
41# Create a public record
42EGOKEY=`gnunet-identity -d | grep testego2 | cut -d' ' -f3`
43gnunet-namestore -a -c $CONFIGURATION -S <<EOF
44$TEST_RECORD_NAME.testego:
45 A 3600000000 [pr] $TEST_IP
46 TXT 21438201833 [r] $TEST_IP2
47
48 TXT 21438201833 [r] aslkdj asdlkjaslkd 232!
49
50$TEST_RECORD_NAME2.testego:
51 AAAA 324241223 [prS] ::dead:beef
52 A 111324241223000000 [pC] 1.1.1.1
53
54www7.$EGOKEY:
55 A 3600000000 [pr] $TEST_IP
56
57EOF
58NAMESTORE_RES=$?
59gnunet-namestore -D -r -c $CONFIGURATION
60stop_peer
61
62if [ $NAMESTORE_RES = 0 ]
63then
64 echo "PASS: Creating name in namestore"
65else
66 echo "FAIL: Creating name in namestore failed with $NAMESTORE_RES."
67 exit 1
68fi
diff --git a/src/cli/namestore/test_namestore_zonefile_import.sh b/src/cli/namestore/test_namestore_zonefile_import.sh
new file mode 100755
index 000000000..d6345257f
--- /dev/null
+++ b/src/cli/namestore/test_namestore_zonefile_import.sh
@@ -0,0 +1,33 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_namestore_api.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_namestore_api.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
19
20MY_EGO="myego"
21gnunet-arm -s -c test_namestore_api.conf
22gnunet-identity -C $MY_EGO -c test_namestore_api.conf
23gnunet-namestore-zonefile -c test_namestore_api.conf < example_zonefile
24res=$?
25gnunet-identity -D $MY_EGO -c test_namestore_api.conf
26gnunet-arm -e -c test_namestore_api.conf
27
28if [ $res != 0 ]; then
29 echo "FAIL: Zone import failed."
30 exit 1
31fi
32
33
diff --git a/src/cli/nat-auto/.gitignore b/src/cli/nat-auto/.gitignore
new file mode 100644
index 000000000..c750bf612
--- /dev/null
+++ b/src/cli/nat-auto/.gitignore
@@ -0,0 +1,2 @@
1gnunet-nat-auto
2gnunet-nat-server
diff --git a/src/cli/nat-auto/Makefile.am b/src/cli/nat-auto/Makefile.am
new file mode 100644
index 000000000..4b2d74280
--- /dev/null
+++ b/src/cli/nat-auto/Makefile.am
@@ -0,0 +1,26 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4libexecdir= $(pkglibdir)/libexec/
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8bin_PROGRAMS = \
9 gnunet-nat-auto \
10 gnunet-nat-server
11
12gnunet_nat_server_SOURCES = \
13 gnunet-nat-server.c
14gnunet_nat_server_LDADD = \
15 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
16 $(top_builddir)/src/lib/util/libgnunetutil.la
17gnunet_nat_server_LDFLAGS = \
18 $(GN_LIBINTL)
19
20gnunet_nat_auto_SOURCES = \
21 gnunet-nat-auto.c
22gnunet_nat_auto_LDADD = \
23 $(top_builddir)/src/service/nat-auto/libgnunetnatauto.la \
24 $(top_builddir)/src/lib/util/libgnunetutil.la
25gnunet_nat_auto_LDFLAGS = \
26 $(GN_LIBINTL)
diff --git a/src/cli/nat-auto/gnunet-nat-auto.c b/src/cli/nat-auto/gnunet-nat-auto.c
new file mode 100644
index 000000000..055a949bd
--- /dev/null
+++ b/src/cli/nat-auto/gnunet-nat-auto.c
@@ -0,0 +1,367 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015, 2016, 2017 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 src/nat/gnunet-nat-auto.c
23 * @brief Command-line tool for testing and autoconfiguration of NAT traversal
24 * @author Christian Grothoff
25 * @author Bruno Cabral
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_nat_service.h"
30#include "gnunet_nat_auto_service.h"
31
32/**
33 * Value to return from #main().
34 */
35static int global_ret;
36
37/**
38 * Handle to ongoing autoconfiguration.
39 */
40static struct GNUNET_NAT_AUTO_AutoHandle *ah;
41
42/**
43 * If we do auto-configuration, should we write the result
44 * to a file?
45 */
46static int write_cfg;
47
48/**
49 * Configuration filename.
50 */
51static const char *cfg_file;
52
53/**
54 * Original configuration.
55 */
56static const struct GNUNET_CONFIGURATION_Handle *cfg;
57
58/**
59 * Adapter we are supposed to test.
60 */
61static char *section_name;
62
63/**
64 * Should we run autoconfiguration?
65 */
66static int do_auto;
67
68/**
69 * Handle to a NAT test operation.
70 */
71static struct GNUNET_NAT_AUTO_Test *nt;
72
73/**
74 * Flag set to 1 if we use IPPROTO_UDP.
75 */
76static int use_udp;
77
78/**
79 * Flag set to 1 if we use IPPROTO_TCP.
80 */
81static int use_tcp;
82
83/**
84 * Protocol to use.
85 */
86static uint8_t proto;
87
88/**
89 * Test if all activities have finished, and if so,
90 * terminate.
91 */
92static void
93test_finished ()
94{
95 if (NULL != ah)
96 return;
97 if (NULL != nt)
98 return;
99 GNUNET_SCHEDULER_shutdown ();
100}
101
102
103/**
104 * Function to iterate over suggested changes options
105 *
106 * @param cls closure
107 * @param section name of the section
108 * @param option name of the option
109 * @param value value of the option
110 */
111static void
112auto_conf_iter (void *cls,
113 const char *section,
114 const char *option,
115 const char *value)
116{
117 struct GNUNET_CONFIGURATION_Handle *new_cfg = cls;
118
119 printf ("%s: %s\n", option, value);
120 if (NULL != new_cfg)
121 GNUNET_CONFIGURATION_set_value_string (new_cfg, section, option, value);
122}
123
124
125/**
126 * Function called with the result from the autoconfiguration.
127 *
128 * @param cls closure
129 * @param diff minimal suggested changes to the original configuration
130 * to make it work (as best as we can)
131 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
132 * @param type what the situation of the NAT
133 */
134static void
135auto_config_cb (void *cls,
136 const struct GNUNET_CONFIGURATION_Handle *diff,
137 enum GNUNET_NAT_StatusCode result,
138 enum GNUNET_NAT_Type type)
139{
140 const char *nat_type;
141 char unknown_type[64];
142 struct GNUNET_CONFIGURATION_Handle *new_cfg;
143
144 ah = NULL;
145 switch (type)
146 {
147 case GNUNET_NAT_TYPE_NO_NAT:
148 nat_type = "NO NAT";
149 break;
150
151 case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
152 nat_type = "NAT but we can traverse";
153 break;
154
155 case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
156 nat_type = "NAT but STUN is able to identify the correct information";
157 break;
158
159 case GNUNET_NAT_TYPE_UPNP_NAT:
160 nat_type = "NAT but UPNP opened the ports";
161 break;
162
163 default:
164 sprintf (unknown_type, "NAT unknown, type %u", type);
165 nat_type = unknown_type;
166 break;
167 }
168
169 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
170 "NAT status: %s/%s\n",
171 GNUNET_NAT_AUTO_status2string (result),
172 nat_type);
173
174 if (NULL == diff)
175 return;
176
177 /* Shortcut: if there are no changes suggested, bail out early. */
178 if (GNUNET_NO == GNUNET_CONFIGURATION_is_dirty (diff))
179 {
180 test_finished ();
181 return;
182 }
183
184 /* Apply diff to original configuration and show changes
185 to the user */
186 new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
187
188 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
189 _ ("Suggested configuration changes:\n"));
190 GNUNET_CONFIGURATION_iterate_section_values (diff,
191 "nat",
192 &auto_conf_iter,
193 new_cfg);
194
195 /* If desired, write configuration to file; we write only the
196 changes to the defaults to keep things compact. */
197 if (write_cfg)
198 {
199 struct GNUNET_CONFIGURATION_Handle *def_cfg;
200
201 GNUNET_CONFIGURATION_set_value_string (new_cfg, "ARM", "CONFIG", NULL);
202 def_cfg = GNUNET_CONFIGURATION_create ();
203 GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_load (def_cfg, NULL));
204 if (GNUNET_OK !=
205 GNUNET_CONFIGURATION_write_diffs (def_cfg, new_cfg, cfg_file))
206 {
207 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
208 _ ("Failed to write configuration to `%s'\n"),
209 cfg_file);
210 global_ret = 1;
211 }
212 else
213 {
214 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
215 _ ("Wrote updated configuration to `%s'\n"),
216 cfg_file);
217 }
218 GNUNET_CONFIGURATION_destroy (def_cfg);
219 }
220
221 if (NULL != new_cfg)
222 GNUNET_CONFIGURATION_destroy (new_cfg);
223 test_finished ();
224}
225
226
227/**
228 * Function called to report success or failure for
229 * NAT configuration test.
230 *
231 * @param cls closure
232 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
233 */
234static void
235test_report_cb (void *cls, enum GNUNET_NAT_StatusCode result)
236{
237 nt = NULL;
238 printf ("NAT test result: %s\n", GNUNET_NAT_AUTO_status2string (result));
239 test_finished ();
240}
241
242
243/**
244 * Task run on shutdown.
245 *
246 * @param cls NULL
247 */
248static void
249do_shutdown (void *cls)
250{
251 if (NULL != ah)
252 {
253 GNUNET_NAT_AUTO_autoconfig_cancel (ah);
254 ah = NULL;
255 }
256 if (NULL != nt)
257 {
258 GNUNET_NAT_AUTO_test_stop (nt);
259 nt = NULL;
260 }
261}
262
263
264/**
265 * Main function that will be run.
266 *
267 * @param cls closure
268 * @param args remaining command-line arguments
269 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
270 * @param c configuration
271 */
272static void
273run (void *cls,
274 char *const *args,
275 const char *cfgfile,
276 const struct GNUNET_CONFIGURATION_Handle *c)
277{
278 cfg_file = cfgfile;
279 cfg = c;
280
281 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
282
283 if (do_auto)
284 {
285 ah = GNUNET_NAT_AUTO_autoconfig_start (c, &auto_config_cb, NULL);
286 }
287
288 if (use_tcp && use_udp)
289 {
290 if (do_auto)
291 return;
292 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n");
293 global_ret = 1;
294 return;
295 }
296 proto = 0;
297 if (use_tcp)
298 proto = IPPROTO_TCP;
299 if (use_udp)
300 proto = IPPROTO_UDP;
301
302 if (NULL != section_name)
303 {
304 nt = GNUNET_NAT_AUTO_test_start (c,
305 proto,
306 section_name,
307 &test_report_cb,
308 NULL);
309 }
310 test_finished ();
311}
312
313
314/**
315 * Main function of gnunet-nat-auto
316 *
317 * @param argc number of command-line arguments
318 * @param argv command line
319 * @return 0 on success, -1 on error
320 */
321int
322main (int argc, char *const argv[])
323{
324 struct GNUNET_GETOPT_CommandLineOption options[] =
325 { GNUNET_GETOPT_option_flag ('a',
326 "auto",
327 gettext_noop ("run autoconfiguration"),
328 &do_auto),
329
330 GNUNET_GETOPT_option_string (
331 'S',
332 "section",
333 "NAME",
334 gettext_noop (
335 "section name providing the configuration for the adapter"),
336 &section_name),
337
338 GNUNET_GETOPT_option_flag ('t', "tcp", gettext_noop ("use TCP"), &use_tcp),
339
340 GNUNET_GETOPT_option_flag ('u', "udp", gettext_noop ("use UDP"), &use_udp),
341
342 GNUNET_GETOPT_option_flag (
343 'w',
344 "write",
345 gettext_noop ("write configuration file (for autoconfiguration)"),
346 &write_cfg),
347 GNUNET_GETOPT_OPTION_END };
348
349 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
350 return 2;
351 if (GNUNET_OK !=
352 GNUNET_PROGRAM_run (argc,
353 argv,
354 "gnunet-nat-auto [options]",
355 _ ("GNUnet NAT traversal autoconfiguration"),
356 options,
357 &run,
358 NULL))
359 {
360 global_ret = 1;
361 }
362 GNUNET_free_nz ((void *) argv);
363 return global_ret;
364}
365
366
367/* end of gnunet-nat-auto.c */
diff --git a/src/cli/nat-auto/gnunet-nat-server.c b/src/cli/nat-auto/gnunet-nat-server.c
new file mode 100644
index 000000000..baa610e8f
--- /dev/null
+++ b/src/cli/nat-auto/gnunet-nat-server.c
@@ -0,0 +1,403 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2017 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 src/nat/gnunet-nat-server.c
23 * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_nat_service.h"
29#include "gnunet_protocols.h"
30// FIXME can we build this without this header?
31#include "../../service/nat-auto/nat-auto.h"
32
33
34/**
35 * Information we track per client.
36 */
37struct ClientData
38{
39 /**
40 * Timeout task.
41 */
42 struct GNUNET_SCHEDULER_Task *tt;
43
44 /**
45 * Client handle.
46 */
47 struct GNUNET_SERVICE_Client *client;
48};
49
50
51/**
52 * Our configuration.
53 */
54static const struct GNUNET_CONFIGURATION_Handle *cfg;
55
56
57/**
58 * Try contacting the peer using autonomous NAT traversal method.
59 *
60 * @param dst_ipv4 IPv4 address to send the fake ICMP message
61 * @param dport destination port to include in ICMP message
62 * @param is_tcp mark for TCP (#GNUNET_YES) or UDP (#GNUNET_NO)
63 */
64static void
65try_anat (uint32_t dst_ipv4,
66 uint16_t dport,
67 int is_tcp)
68{
69 struct GNUNET_NAT_Handle *h;
70 struct sockaddr_in lsa;
71 struct sockaddr_in rsa;
72 const struct sockaddr *sa;
73 socklen_t sa_len;
74
75 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
76 "Asking for connection reversal with %x and code %u\n",
77 (unsigned int) dst_ipv4,
78 (unsigned int) dport);
79 memset (&lsa, 0, sizeof(lsa));
80 lsa.sin_family = AF_INET;
81#if HAVE_SOCKADDR_IN_SIN_LEN
82 lsa.sin_len = sizeof(sa);
83#endif
84 lsa.sin_addr.s_addr = 0;
85 lsa.sin_port = htons (dport);
86 memset (&rsa, 0, sizeof(rsa));
87 rsa.sin_family = AF_INET;
88#if HAVE_SOCKADDR_IN_SIN_LEN
89 rsa.sin_len = sizeof(sa);
90#endif
91 rsa.sin_addr.s_addr = dst_ipv4;
92 rsa.sin_port = htons (dport);
93 sa_len = sizeof(lsa);
94 sa = (const struct sockaddr *) &lsa;
95 h = GNUNET_NAT_register (cfg,
96 "none",
97 is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
98 1,
99 &sa,
100 &sa_len,
101 NULL, NULL, NULL);
102 GNUNET_NAT_request_reversal (h,
103 &lsa,
104 &rsa);
105 GNUNET_NAT_unregister (h);
106}
107
108
109/**
110 * Closure for #tcp_send.
111 */
112struct TcpContext
113{
114 /**
115 * TCP socket.
116 */
117 struct GNUNET_NETWORK_Handle *s;
118
119 /**
120 * Data to transmit.
121 */
122 uint16_t data;
123};
124
125
126/**
127 * Task called by the scheduler once we can do the TCP send
128 * (or once we failed to connect...).
129 *
130 * @param cls the `struct TcpContext`
131 */
132static void
133tcp_send (void *cls)
134{
135 struct TcpContext *ctx = cls;
136 const struct GNUNET_SCHEDULER_TaskContext *tc;
137
138 tc = GNUNET_SCHEDULER_get_task_context ();
139 if ((NULL != tc->write_ready) &&
140 (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
141 {
142 if (-1 ==
143 GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof(ctx->data)))
144 {
145 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
146 }
147 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
148 }
149 GNUNET_NETWORK_socket_close (ctx->s);
150 GNUNET_free (ctx);
151}
152
153
154/**
155 * Try to send @a data to the
156 * IP @a dst_ipv4' at port @a dport via TCP.
157 *
158 * @param dst_ipv4 target IP
159 * @param dport target port
160 * @param data data to send
161 */
162static void
163try_send_tcp (uint32_t dst_ipv4,
164 uint16_t dport,
165 uint16_t data)
166{
167 struct GNUNET_NETWORK_Handle *s;
168 struct sockaddr_in sa;
169 struct TcpContext *ctx;
170
171 s = GNUNET_NETWORK_socket_create (AF_INET,
172 SOCK_STREAM,
173 0);
174 if (NULL == s)
175 {
176 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
177 "socket");
178 return;
179 }
180 memset (&sa, 0, sizeof(sa));
181 sa.sin_family = AF_INET;
182#if HAVE_SOCKADDR_IN_SIN_LEN
183 sa.sin_len = sizeof(sa);
184#endif
185 sa.sin_addr.s_addr = dst_ipv4;
186 sa.sin_port = htons (dport);
187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
188 "Sending TCP message to `%s'\n",
189 GNUNET_a2s ((struct sockaddr *) &sa,
190 sizeof(sa)));
191 if ((GNUNET_OK !=
192 GNUNET_NETWORK_socket_connect (s,
193 (const struct sockaddr *) &sa,
194 sizeof(sa))) &&
195 (errno != EINPROGRESS))
196 {
197 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
198 "connect");
199 GNUNET_NETWORK_socket_close (s);
200 return;
201 }
202 ctx = GNUNET_new (struct TcpContext);
203 ctx->s = s;
204 ctx->data = data;
205 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
206 s,
207 &tcp_send,
208 ctx);
209}
210
211
212/**
213 * Try to send @a data to the
214 * IP @a dst_ipv4 at port @a dport via UDP.
215 *
216 * @param dst_ipv4 target IP
217 * @param dport target port
218 * @param data data to send
219 */
220static void
221try_send_udp (uint32_t dst_ipv4,
222 uint16_t dport,
223 uint16_t data)
224{
225 struct GNUNET_NETWORK_Handle *s;
226 struct sockaddr_in sa;
227
228 s = GNUNET_NETWORK_socket_create (AF_INET,
229 SOCK_DGRAM,
230 0);
231 if (NULL == s)
232 {
233 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
234 "socket");
235 return;
236 }
237 memset (&sa, 0, sizeof(sa));
238 sa.sin_family = AF_INET;
239#if HAVE_SOCKADDR_IN_SIN_LEN
240 sa.sin_len = sizeof(sa);
241#endif
242 sa.sin_addr.s_addr = dst_ipv4;
243 sa.sin_port = htons (dport);
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 "Sending UDP packet to `%s'\n",
246 GNUNET_a2s ((struct sockaddr *) &sa,
247 sizeof(sa)));
248 if (-1 ==
249 GNUNET_NETWORK_socket_sendto (s,
250 &data,
251 sizeof(data),
252 (const struct sockaddr *) &sa,
253 sizeof(sa)))
254 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
255 "sendto");
256 GNUNET_NETWORK_socket_close (s);
257}
258
259
260/**
261 * We've received a request to probe a NAT
262 * traversal. Do it.
263 *
264 * @param cls handle to client (we always close)
265 * @param tm message with details about what to test
266 */
267static void
268handle_test (void *cls,
269 const struct GNUNET_NAT_AUTO_TestMessage *tm)
270{
271 struct ClientData *cd = cls;
272 uint16_t dport;
273
274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275 "Received test request\n");
276 dport = ntohs (tm->dport);
277 if (0 == dport)
278 try_anat (tm->dst_ipv4,
279 ntohs (tm->data),
280 (int) ntohl (tm->is_tcp));
281 else if (GNUNET_YES == ntohl (tm->is_tcp))
282 try_send_tcp (tm->dst_ipv4,
283 dport,
284 tm->data);
285 else
286 try_send_udp (tm->dst_ipv4,
287 dport,
288 tm->data);
289 GNUNET_SERVICE_client_drop (cd->client);
290}
291
292
293/**
294 * Main function that will be run.
295 *
296 * @param cls closure
297 * @param c configuration
298 * @param srv service handle
299 */
300static void
301run (void *cls,
302 const struct GNUNET_CONFIGURATION_Handle *c,
303 struct GNUNET_SERVICE_Handle *srv)
304{
305 cfg = c;
306}
307
308
309/**
310 * Forcefully drops client after 1s.
311 *
312 * @param cls our `struct ClientData` of a client to drop
313 */
314static void
315force_timeout (void *cls)
316{
317 struct ClientData *cd = cls;
318
319 cd->tt = NULL;
320 GNUNET_SERVICE_client_drop (cd->client);
321}
322
323
324/**
325 * Callback called when a client connects to the service.
326 *
327 * @param cls closure for the service
328 * @param c the new client that connected to the service
329 * @param mq the message queue used to send messages to the client
330 * @return our `struct ClientData`
331 */
332static void *
333client_connect_cb (void *cls,
334 struct GNUNET_SERVICE_Client *c,
335 struct GNUNET_MQ_Handle *mq)
336{
337 struct ClientData *cd;
338
339 cd = GNUNET_new (struct ClientData);
340 cd->client = c;
341 cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
342 &force_timeout,
343 cd);
344 return cd;
345}
346
347
348/**
349 * Callback called when a client disconnected from the service
350 *
351 * @param cls closure for the service
352 * @param c the client that disconnected
353 * @param internal_cls our `struct ClientData`
354 */
355static void
356client_disconnect_cb (void *cls,
357 struct GNUNET_SERVICE_Client *c,
358 void *internal_cls)
359{
360 struct ClientData *cd = internal_cls;
361
362 if (NULL != cd->tt)
363 GNUNET_SCHEDULER_cancel (cd->tt);
364 GNUNET_free (cd);
365}
366
367
368/**
369 * Define "main" method using service macro.
370 */
371GNUNET_SERVICE_MAIN
372 ("nat-server",
373 GNUNET_SERVICE_OPTION_NONE,
374 &run,
375 &client_connect_cb,
376 &client_disconnect_cb,
377 NULL,
378 GNUNET_MQ_hd_fixed_size (test,
379 GNUNET_MESSAGE_TYPE_NAT_TEST,
380 struct GNUNET_NAT_AUTO_TestMessage,
381 NULL),
382 GNUNET_MQ_handler_end ());
383
384
385#if defined(__linux__) && defined(__GLIBC__)
386#include <malloc.h>
387
388/**
389 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
390 */
391void __attribute__ ((constructor))
392GNUNET_ARM_memory_init ()
393{
394 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
395 mallopt (M_TOP_PAD, 1 * 1024);
396 malloc_trim (0);
397}
398
399
400#endif
401
402
403/* end of gnunet-nat-server.c */
diff --git a/src/cli/nat-auto/meson.build b/src/cli/nat-auto/meson.build
new file mode 100644
index 000000000..69e719126
--- /dev/null
+++ b/src/cli/nat-auto/meson.build
@@ -0,0 +1,14 @@
1executable ('gnunet-nat-auto',
2 ['gnunet-nat-auto.c'],
3 dependencies: [libgnunetnatauto_dep, libgnunetutil_dep,
4 libgnunetnat_dep],
5 include_directories: [incdir, configuration_inc],
6 install: true,
7 install_dir: get_option('bindir'))
8executable ('gnunet-nat-server',
9 ['gnunet-nat-server.c'],
10 dependencies: [libgnunetnatauto_dep, libgnunetutil_dep, libgnunetnat_dep],
11 include_directories: [incdir, configuration_inc],
12 install: true,
13 install_dir: get_option('bindir'))
14
diff --git a/src/cli/nat/.gitignore b/src/cli/nat/.gitignore
new file mode 100644
index 000000000..89e635e9f
--- /dev/null
+++ b/src/cli/nat/.gitignore
@@ -0,0 +1 @@
gnunet-nat
diff --git a/src/cli/nat/Makefile.am b/src/cli/nat/Makefile.am
new file mode 100644
index 000000000..1bdd1a6be
--- /dev/null
+++ b/src/cli/nat/Makefile.am
@@ -0,0 +1,17 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4libexecdir= $(pkglibdir)/libexec/
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8bin_PROGRAMS = \
9 gnunet-nat
10
11gnunet_nat_SOURCES = \
12 gnunet-nat.c
13gnunet_nat_LDADD = \
14 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
15 $(top_builddir)/src/lib/util/libgnunetutil.la
16gnunet_nat_LDFLAGS = \
17 $(GN_LIBINTL)
diff --git a/src/cli/nat/gnunet-nat.c b/src/cli/nat/gnunet-nat.c
new file mode 100644
index 000000000..fd85549d6
--- /dev/null
+++ b/src/cli/nat/gnunet-nat.c
@@ -0,0 +1,476 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015, 2016 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 src/nat/gnunet-nat.c
23 * @brief Command-line tool to interact with the NAT service
24 * @author Christian Grothoff
25 * @author Bruno Cabral
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_nat_service.h"
30
31/**
32 * Value to return from #main().
33 */
34static int global_ret;
35
36/**
37 * Name of section in configuration file to use for
38 * additional options.
39 */
40static char *section_name;
41
42/**
43 * Flag set to 1 if we use IPPROTO_UDP.
44 */
45static int use_udp;
46
47/**
48 * Flag set to 1 if we are to listen for connection reversal requests.
49 */
50static int listen_reversal;
51
52/**
53 * Flag set to 1 if we use IPPROTO_TCP.
54 */
55static int use_tcp;
56
57/**
58 * Protocol to use.
59 */
60static uint8_t proto;
61
62/**
63 * Local address to use for connection reversal request.
64 */
65static char *local_addr;
66
67/**
68 * Remote address to use for connection reversal request.
69 */
70static char *remote_addr;
71
72/**
73 * Should we actually bind to #bind_addr and receive and process STUN requests?
74 */
75static int do_stun;
76
77/**
78 * Handle to NAT operation.
79 */
80static struct GNUNET_NAT_Handle *nh;
81
82/**
83 * Listen socket for STUN processing.
84 */
85static struct GNUNET_NETWORK_Handle *ls;
86
87/**
88 * Task for reading STUN packets.
89 */
90static struct GNUNET_SCHEDULER_Task *rtask;
91
92
93/**
94 * Test if all activities have finished, and if so,
95 * terminate.
96 */
97static void
98test_finished ()
99{
100 if (NULL != nh)
101 return;
102 if (NULL != rtask)
103 return;
104 GNUNET_SCHEDULER_shutdown ();
105}
106
107
108/**
109 * Signature of the callback passed to #GNUNET_NAT_register() for
110 * a function to call whenever our set of 'valid' addresses changes.
111 *
112 * @param cls closure, NULL
113 * @param[in,out] app_ctx location where the app can store stuff
114 * on add and retrieve it on remove
115 * @param add_remove #GNUNET_YES to add a new public IP address,
116 * #GNUNET_NO to remove a previous (now invalid) one
117 * @param ac address class the address belongs to
118 * @param addr either the previous or the new public IP address
119 * @param addrlen actual length of the @a addr
120 */
121static void
122address_cb (void *cls,
123 void **app_ctx,
124 int add_remove,
125 enum GNUNET_NAT_AddressClass ac,
126 const struct sockaddr *addr,
127 socklen_t addrlen)
128{
129 (void) cls;
130 (void) app_ctx;
131
132 fprintf (stdout,
133 "%s %s (%d)\n",
134 add_remove ? "+" : "-",
135 GNUNET_a2s (addr, addrlen),
136 (int) ac);
137}
138
139
140/**
141 * Signature of the callback passed to #GNUNET_NAT_register().
142 * for a function to call whenever someone asks us to do connection
143 * reversal.
144 *
145 * @param cls closure, NULL
146 * @param remote_addr public IP address of the other peer
147 * @param remote_addrlen actual length of the @a remote_addr
148 */
149static void
150reversal_cb (void *cls,
151 const struct sockaddr *remote_addr,
152 socklen_t remote_addrlen)
153{
154 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
155 "Connection reversal requested by %s\n",
156 GNUNET_a2s (remote_addr, remote_addrlen));
157}
158
159
160/**
161 * Task run on shutdown.
162 *
163 * @param cls NULL
164 */
165static void
166do_shutdown (void *cls)
167{
168 if (NULL != nh)
169 {
170 GNUNET_NAT_unregister (nh);
171 nh = NULL;
172 }
173 if (NULL != ls)
174 {
175 GNUNET_NETWORK_socket_close (ls);
176 ls = NULL;
177 }
178 if (NULL != rtask)
179 {
180 GNUNET_SCHEDULER_cancel (rtask);
181 rtask = NULL;
182 }
183}
184
185
186/**
187 * Task to receive incoming packets for STUN processing.
188 */
189static void
190stun_read_task (void *cls)
191{
192 ssize_t size;
193
194 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
195 ls,
196 &stun_read_task,
197 NULL);
198 size = GNUNET_NETWORK_socket_recvfrom_amount (ls);
199 if (size > 0)
200 {
201 GNUNET_break (0);
202 GNUNET_SCHEDULER_shutdown ();
203 global_ret = 1;
204 return;
205 }
206 {
207 char buf[size + 1];
208 struct sockaddr_storage sa;
209 socklen_t salen = sizeof(sa);
210 ssize_t ret;
211
212 ret = GNUNET_NETWORK_socket_recvfrom (ls,
213 buf,
214 size + 1,
215 (struct sockaddr *) &sa,
216 &salen);
217 if (ret != size)
218 {
219 GNUNET_break (0);
220 GNUNET_SCHEDULER_shutdown ();
221 global_ret = 1;
222 return;
223 }
224 (void) GNUNET_NAT_stun_handle_packet (nh,
225 (const struct sockaddr *) &sa,
226 salen,
227 buf,
228 ret);
229 }
230}
231
232
233/**
234 * Main function that will be run.
235 *
236 * @param cls closure
237 * @param args remaining command-line arguments
238 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
239 * @param c configuration
240 */
241static void
242run (void *cls,
243 char *const *args,
244 const char *cfgfile,
245 const struct GNUNET_CONFIGURATION_Handle *c)
246{
247 uint8_t af;
248 struct sockaddr *local_sa;
249 struct sockaddr *remote_sa;
250 socklen_t local_len;
251 size_t remote_len;
252
253 if (use_tcp && use_udp)
254 {
255 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n");
256 global_ret = 1;
257 return;
258 }
259 proto = 0;
260 if (use_tcp)
261 proto = IPPROTO_TCP;
262 if (use_udp)
263 proto = IPPROTO_UDP;
264
265 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
266
267 if (0 == proto)
268 {
269 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Must specify either TCP or UDP\n");
270 global_ret = 1;
271 return;
272 }
273 local_len = 0;
274 local_sa = NULL;
275 remote_len = 0;
276 remote_sa = NULL;
277 if (NULL != local_addr)
278 {
279 local_len =
280 (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, &af, &local_sa);
281 if (0 == local_len)
282 {
283 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
284 "Invalid socket address `%s'\n",
285 local_addr);
286 goto fail_and_shutdown;
287 }
288 }
289
290 if (NULL != remote_addr)
291 {
292 remote_len =
293 GNUNET_STRINGS_parse_socket_addr (remote_addr, &af, &remote_sa);
294 if (0 == remote_len)
295 {
296 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
297 "Invalid socket address `%s'\n",
298 remote_addr);
299 goto fail_and_shutdown;
300 }
301 }
302
303 if (NULL != local_addr)
304 {
305 if (NULL == section_name)
306 section_name = GNUNET_strdup ("undefined");
307 nh = GNUNET_NAT_register (c,
308 section_name,
309 proto,
310 1,
311 (const struct sockaddr **) &local_sa,
312 &local_len,
313 &address_cb,
314 (listen_reversal) ? &reversal_cb : NULL,
315 NULL);
316 }
317 else if (listen_reversal)
318 {
319 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
320 "Use of `-W` only effective in combination with `-i`\n");
321 goto fail_and_shutdown;
322 }
323
324 if (NULL != remote_addr)
325 {
326 int ret;
327
328 if ((NULL == nh) || (sizeof(struct sockaddr_in) != local_len))
329 {
330 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
331 "Require IPv4 local address to initiate connection reversal\n");
332 goto fail_and_shutdown;
333 }
334 if (sizeof(struct sockaddr_in) != remote_len)
335 {
336 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
337 "Require IPv4 reversal target address\n");
338 goto fail_and_shutdown;
339 }
340 GNUNET_assert (AF_INET == local_sa->sa_family);
341 GNUNET_assert (AF_INET == remote_sa->sa_family);
342 ret = GNUNET_NAT_request_reversal (nh,
343 (const struct sockaddr_in *) local_sa,
344 (const struct sockaddr_in *) remote_sa);
345 switch (ret)
346 {
347 case GNUNET_SYSERR:
348 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
349 "Connection reversal internal error\n");
350 break;
351
352 case GNUNET_NO:
353 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
354 "Connection reversal unavailable\n");
355 break;
356
357 case GNUNET_OK:
358 /* operation in progress */
359 break;
360 }
361 }
362
363 if (do_stun)
364 {
365 if (NULL == local_addr)
366 {
367 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
368 "Require local address to support STUN requests\n");
369 goto fail_and_shutdown;
370 }
371 if (IPPROTO_UDP != proto)
372 {
373 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "STUN only supported over UDP\n");
374 goto fail_and_shutdown;
375 }
376 ls = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, IPPROTO_UDP);
377 if (NULL == ls)
378 {
379 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Failed to create socket\n");
380 goto fail_and_shutdown;
381 }
382 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls, local_sa, local_len))
383 {
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Failed to bind to %s: %s\n",
386 GNUNET_a2s (local_sa, local_len),
387 strerror (errno));
388 goto fail_and_shutdown;
389 }
390 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
391 ls,
392 &stun_read_task,
393 NULL);
394 }
395 GNUNET_free (remote_sa);
396 GNUNET_free (local_sa);
397 test_finished ();
398 return;
399fail_and_shutdown:
400 global_ret = 1;
401 GNUNET_SCHEDULER_shutdown ();
402 GNUNET_free (remote_sa);
403 GNUNET_free (local_sa);
404}
405
406
407/**
408 * Main function of gnunet-nat
409 *
410 * @param argc number of command-line arguments
411 * @param argv command line
412 * @return 0 on success, -1 on error
413 */
414int
415main (int argc, char *const argv[])
416{
417 struct GNUNET_GETOPT_CommandLineOption options[] = {
418 GNUNET_GETOPT_option_string (
419 'i',
420 "in",
421 "ADDRESS",
422 gettext_noop ("which IP and port are we locally using to bind/listen to"),
423 &local_addr),
424
425 GNUNET_GETOPT_option_string (
426 'r',
427 "remote",
428 "ADDRESS",
429 gettext_noop (
430 "which remote IP and port should be asked for connection reversal"),
431 &remote_addr),
432
433 GNUNET_GETOPT_option_string (
434 'S',
435 "section",
436 NULL,
437 gettext_noop (
438 "name of configuration section to find additional options, such as manual host punching data"),
439 &section_name),
440
441 GNUNET_GETOPT_option_flag ('s',
442 "stun",
443 gettext_noop ("enable STUN processing"),
444 &do_stun),
445
446 GNUNET_GETOPT_option_flag ('t', "tcp", gettext_noop ("use TCP"), &use_tcp),
447
448 GNUNET_GETOPT_option_flag ('u', "udp", gettext_noop ("use UDP"), &use_udp),
449
450 GNUNET_GETOPT_option_flag ('W',
451 "watch",
452 gettext_noop (
453 "watch for connection reversal requests"),
454 &listen_reversal),
455 GNUNET_GETOPT_OPTION_END
456 };
457
458 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
459 return 2;
460 if (GNUNET_OK !=
461 GNUNET_PROGRAM_run (argc,
462 argv,
463 "gnunet-nat [options]",
464 _ ("GNUnet NAT traversal autoconfigure daemon"),
465 options,
466 &run,
467 NULL))
468 {
469 global_ret = 1;
470 }
471 GNUNET_free_nz ((void *) argv);
472 return global_ret;
473}
474
475
476/* end of gnunet-nat.c */
diff --git a/src/cli/nat/meson.build b/src/cli/nat/meson.build
new file mode 100644
index 000000000..41af0c087
--- /dev/null
+++ b/src/cli/nat/meson.build
@@ -0,0 +1,7 @@
1executable ('gnunet-nat',
2 ['gnunet-nat.c'],
3 dependencies: [libgnunetnat_dep, libgnunetutil_dep],
4 include_directories: [incdir, configuration_inc],
5 install: true,
6 install_dir: get_option('bindir'))
7
diff --git a/src/cli/nse/.gitignore b/src/cli/nse/.gitignore
new file mode 100644
index 000000000..ec3c6a9cf
--- /dev/null
+++ b/src/cli/nse/.gitignore
@@ -0,0 +1 @@
gnunet-nse
diff --git a/src/cli/nse/Makefile.am b/src/cli/nse/Makefile.am
new file mode 100644
index 000000000..e724a22d3
--- /dev/null
+++ b/src/cli/nse/Makefile.am
@@ -0,0 +1,19 @@
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
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13bin_PROGRAMS = gnunet-nse
14
15gnunet_nse_SOURCES = gnunet-nse.c
16gnunet_nse_LDADD = \
17 $(top_builddir)/src/service/nse/libgnunetnse.la \
18 $(top_builddir)/src/lib/util/libgnunetutil.la \
19 $(XLIB) $(GN_LIBINTL)
diff --git a/src/cli/nse/gnunet-nse.c b/src/cli/nse/gnunet-nse.c
new file mode 100644
index 000000000..b88697695
--- /dev/null
+++ b/src/cli/nse/gnunet-nse.c
@@ -0,0 +1,143 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2014, 2016 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 nse/gnunet-nse.c
23 * @brief Program to display network size estimates from the NSE service
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_nse_service.h"
29#include <gnunet_util_lib.h>
30
31/**
32 * The handle to the NSE service
33 */
34static struct GNUNET_NSE_Handle *nse;
35
36/**
37 * The program status; 0 for success.
38 */
39static int status;
40
41/**
42 * Monitor flag.
43 */
44static int monitor;
45
46
47/**
48 * Task to shutdown and clean up all state
49 *
50 * @param cls NULL
51 */
52static void
53do_shutdown (void *cls)
54{
55 (void) cls;
56 if (NULL != nse)
57 {
58 GNUNET_NSE_disconnect (nse);
59 nse = NULL;
60 }
61}
62
63
64/**
65 * Callback to call when network size estimate is updated.
66 *
67 * @param cls NULL
68 * @param timestamp server timestamp
69 * @param estimate the value of the current network size estimate
70 * @param std_dev standard deviation (rounded down to nearest integer)
71 * of the size estimation values seen
72 */
73static void
74handle_estimate (void *cls,
75 struct GNUNET_TIME_Absolute timestamp,
76 double estimate,
77 double std_dev)
78{
79 (void) cls;
80 status = 0;
81 fprintf (stdout,
82 "%s: #peers=%f (ld(#peers)=%f, stddev=%f)\n",
83 GNUNET_STRINGS_absolute_time_to_string (timestamp),
84 GNUNET_NSE_log_estimate_to_n (estimate),
85 estimate,
86 std_dev);
87 if (! monitor)
88 GNUNET_SCHEDULER_shutdown ();
89}
90
91
92/**
93 * Actual main function that runs the emulation.
94 *
95 * @param cls unused
96 * @param args remaining args, unused
97 * @param cfgfile name of the configuration
98 * @param cfg configuration handle
99 */
100static void
101run (void *cls,
102 char *const *args,
103 const char *cfgfile,
104 const struct GNUNET_CONFIGURATION_Handle *cfg)
105{
106 (void) cls;
107 (void) args;
108 (void) cfgfile;
109 nse = GNUNET_NSE_connect (cfg, &handle_estimate, NULL);
110 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
111}
112
113
114/**
115 * Main function.
116 *
117 * @return 0 on success
118 */
119int
120main (int argc, char *const *argv)
121{
122 struct GNUNET_GETOPT_CommandLineOption options[] = {
123 GNUNET_GETOPT_option_flag ('m',
124 "monitor",
125 gettext_noop (
126 "Monitor and output current estimates"),
127 &monitor),
128 GNUNET_GETOPT_OPTION_END
129 };
130
131 status = 1;
132 if (GNUNET_OK !=
133 GNUNET_PROGRAM_run (argc,
134 argv,
135 "gnunet-nse",
136 gettext_noop (
137 "Show network size estimates from NSE service."),
138 options,
139 &run,
140 NULL))
141 return 2;
142 return status;
143}
diff --git a/src/cli/nse/meson.build b/src/cli/nse/meson.build
new file mode 100644
index 000000000..584c7eb71
--- /dev/null
+++ b/src/cli/nse/meson.build
@@ -0,0 +1,7 @@
1executable ('gnunet-nse',
2 ['gnunet-nse.c'],
3 dependencies: [libgnunetnse_dep, m_dep, libgnunetutil_dep],
4 include_directories: [incdir, configuration_inc],
5 install: true,
6 install_dir: get_option('bindir'))
7
diff --git a/src/cli/peerstore/.gitignore b/src/cli/peerstore/.gitignore
new file mode 100644
index 000000000..3ae0f6c6c
--- /dev/null
+++ b/src/cli/peerstore/.gitignore
@@ -0,0 +1 @@
gnunet-peerstore
diff --git a/src/cli/peerstore/Makefile.am b/src/cli/peerstore/Makefile.am
new file mode 100644
index 000000000..f5be82f09
--- /dev/null
+++ b/src/cli/peerstore/Makefile.am
@@ -0,0 +1,23 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10if USE_COVERAGE
11 AM_CFLAGS = -fprofile-arcs -ftest-coverage
12endif
13
14# This program does not do anything.
15noinst_PROGRAMS = \
16 gnunet-peerstore
17
18gnunet_peerstore_SOURCES = \
19 gnunet-peerstore.c
20gnunet_peerstore_LDADD = \
21 $(top_builddir)/src/lib/util/libgnunetutil.la \
22 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
23 $(GN_LIBINTL)
diff --git a/src/cli/peerstore/gnunet-peerstore.c b/src/cli/peerstore/gnunet-peerstore.c
new file mode 100644
index 000000000..84cae675f
--- /dev/null
+++ b/src/cli/peerstore/gnunet-peerstore.c
@@ -0,0 +1,97 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C)
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 peerstore/gnunet-peerstore.c
23 * @brief peerstore tool
24 * @author Omar Tarabai
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_peerstore_service.h"
29
30static int ret;
31
32/*
33 * Handle to PEERSTORE service
34 */
35static struct GNUNET_PEERSTORE_Handle *peerstore_handle;
36
37
38/**
39 * Run on shutdown
40 *
41 * @param cls unused
42 */
43static void
44shutdown_task (void *cls)
45{
46 if (NULL != peerstore_handle)
47 {
48 GNUNET_PEERSTORE_disconnect (peerstore_handle);
49 peerstore_handle = NULL;
50 }
51}
52
53
54/**
55 * Main function that will be run by the scheduler.
56 *
57 * @param cls closure
58 * @param args remaining command-line arguments
59 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
60 * @param cfg configuration
61 */
62static void
63run (void *cls,
64 char *const *args,
65 const char *cfgfile,
66 const struct GNUNET_CONFIGURATION_Handle *cfg)
67{
68 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
69 NULL);
70 peerstore_handle = GNUNET_PEERSTORE_connect (cfg);
71 GNUNET_assert (NULL != peerstore_handle);
72 ret = 0;
73}
74
75
76/**
77 * The main function to peerstore.
78 *
79 * @param argc number of arguments from the command line
80 * @param argv command line arguments
81 * @return 0 ok, 1 on error
82 */
83int
84main (int argc, char *const *argv)
85{
86 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
87 GNUNET_GETOPT_OPTION_END
88 };
89
90 return (GNUNET_OK ==
91 GNUNET_PROGRAM_run (argc, argv, "gnunet-peerstore [options [value]]",
92 gettext_noop ("peerstore"), options, &run,
93 NULL)) ? ret : 1;
94}
95
96
97/* end of gnunet-peerstore.c */
diff --git a/src/cli/peerstore/meson.build b/src/cli/peerstore/meson.build
new file mode 100644
index 000000000..1fd177734
--- /dev/null
+++ b/src/cli/peerstore/meson.build
@@ -0,0 +1,9 @@
1executable ('gnunet-peerstore',
2 'gnunet-peerstore.c',
3 dependencies: [libgnunetpeerstore_dep,
4 libgnunetutil_dep
5 ],
6 include_directories: [incdir, configuration_inc],
7 install: false,
8 install_dir: get_option('bindir'))
9
diff --git a/src/cli/reclaim/.gitignore b/src/cli/reclaim/.gitignore
new file mode 100644
index 000000000..49e84eb66
--- /dev/null
+++ b/src/cli/reclaim/.gitignore
@@ -0,0 +1,2 @@
1gnunet-reclaim
2gnunet-did
diff --git a/src/cli/reclaim/Makefile.am b/src/cli/reclaim/Makefile.am
new file mode 100644
index 000000000..9803ac7ac
--- /dev/null
+++ b/src/cli/reclaim/Makefile.am
@@ -0,0 +1,57 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4 plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11
12EXTRA_DIST = \
13 test_reclaim_defaults.conf \
14 test_reclaim.conf \
15 $(check_SCRIPTS)
16
17pkgcfgdir= $(pkgdatadir)/config.d/
18
19libexecdir= $(pkglibdir)/libexec/
20
21bin_PROGRAMS = \
22 gnunet-reclaim \
23 gnunet-did
24
25gnunet_reclaim_SOURCES = \
26 gnunet-reclaim.c
27gnunet_reclaim_LDADD = \
28 $(top_builddir)/src/lib/util/libgnunetutil.la \
29 $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
30 $(top_builddir)/src/service/reclaim/libgnunetreclaim.la \
31 $(top_builddir)/src/service/identity/libgnunetidentity.la \
32 $(GN_LIBINTL)
33
34gnunet_did_SOURCES = \
35 gnunet-did.c
36gnunet_did_LDADD = \
37 $(top_builddir)/src/lib/util/libgnunetutil.la \
38 $(top_builddir)/src/service/gns/libgnunetgns.la \
39 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
40 $(top_builddir)/src/service/identity/libgnunetidentity.la \
41 $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
42 $(top_builddir)/src/service/reclaim/libgnunetdid.la \
43 -ljansson
44gnunet_did_CFLAGS = \
45 -I$(top_builddir)/src/service/reclaim
46
47check_SCRIPTS = \
48 test_reclaim_attribute.sh \
49 test_reclaim_issue.sh \
50 test_reclaim_consume.sh
51
52if ENABLE_TEST_RUN
53 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
54 TESTS = \
55 $(check_SCRIPTS) \
56 $(check_PROGRAMS)
57endif
diff --git a/src/cli/reclaim/gnunet-did.c b/src/cli/reclaim/gnunet-did.c
new file mode 100644
index 000000000..a8ac7652e
--- /dev/null
+++ b/src/cli/reclaim/gnunet-did.c
@@ -0,0 +1,661 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-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 * FIXME: Do we only want to handle EdDSA identities?
23 * TODO: Own GNS record type
24 * TODO: Fix overwrite of records in @ if present look for other with same sub
25 * TODO. Tests
26 * TODO: Move constants to did.h
27 * FIXME: Remove and lookup require differnt representations (did vs egoname)
28 */
29
30/**
31 * @author Tristan Schwieren
32 * @file src/did/gnunet-did.c
33 * @brief DID Method Wrapper
34 */
35#include "platform.h"
36#include "gnunet_util_lib.h"
37#include "gnunet_namestore_service.h"
38#include "gnunet_identity_service.h"
39#include "gnunet_gns_service.h"
40#include "gnunet_gnsrecord_lib.h"
41#include "did_core.h"
42
43#define GNUNET_DID_DEFAULT_DID_DOCUMENT_EXPIRATION_TIME "1d"
44
45/**
46 * return value
47 */
48static int ret;
49
50/**
51 * Replace DID Document Flag
52 */
53static int replace;
54
55/**
56 * Remove DID Document Flag
57 */
58static int remove_did;
59
60/**
61 * Get DID Documement for DID Flag
62 */
63static int get;
64
65/**
66 * Create DID Document Flag
67 */
68static int create;
69
70/**
71 * Show DID for Ego Flag
72 */
73static int show;
74
75/**
76 * Show DID for Ego Flag
77 */
78static int show_all;
79
80/**
81 * DID Attribut String
82 */
83static char *did;
84
85/**
86 * DID Document Attribut String
87 */
88static char *didd;
89
90/**
91 * Ego Attribut String
92 */
93static char *egoname;
94
95/**
96 * DID Document expiration Date Attribut String
97 */
98static char *expire;
99
100/*
101 * Handle to the GNS service
102 */
103static struct GNUNET_GNS_Handle *gns_handle;
104
105/*
106 * Handle to the NAMESTORE service
107 */
108static struct GNUNET_NAMESTORE_Handle *namestore_handle;
109
110/*
111 * Handle to the IDENTITY service
112 */
113static struct GNUNET_IDENTITY_Handle *identity_handle;
114
115
116/*
117 * The configuration
118 */
119const static struct GNUNET_CONFIGURATION_Handle *my_cfg;
120
121/**
122 * Give ego exists
123 */
124static int ego_exists = 0;
125
126/**
127 * @brief Disconnect and shutdown
128 * @param cls closure
129 */
130static void
131cleanup (void *cls)
132{
133 if (NULL != gns_handle)
134 GNUNET_GNS_disconnect (gns_handle);
135 if (NULL != namestore_handle)
136 GNUNET_NAMESTORE_disconnect (namestore_handle);
137 if (NULL != identity_handle)
138 GNUNET_IDENTITY_disconnect (identity_handle);
139
140 GNUNET_free (did);
141 GNUNET_free (didd);
142 GNUNET_free (egoname);
143 GNUNET_free (expire);
144
145 GNUNET_SCHEDULER_shutdown ();
146}
147
148
149/**
150 * @brief GNS lookup callback. Prints the DID Document to standard out.
151 * Fails if there is more than one DID record.
152 *
153 * @param cls closure
154 * @param rd_count number of records in @a rd
155 * @param rd the records in the reply
156 */
157static void
158print_did_document (
159 enum GNUNET_GenericReturnValue status,
160 char *did_document,
161 void *cls
162 )
163{
164 if (GNUNET_OK == status)
165 printf ("%s\n", did_document);
166 else
167 printf ("An error occured: %s\n", did_document);
168
169 GNUNET_SCHEDULER_add_now (cleanup, NULL);
170 ret = 0;
171 return;
172}
173
174
175/**
176 * @brief Resolve a DID given by the user.
177 */
178static void
179resolve_did ()
180{
181
182 if (did == NULL)
183 {
184 printf ("Set DID option to resolve DID\n");
185 GNUNET_SCHEDULER_add_now (cleanup, NULL);
186 ret = 1;
187 return;
188 }
189
190 if (GNUNET_OK != DID_resolve (did, gns_handle, print_did_document, NULL))
191 {
192 printf ("An error occured while resoling the DID\n");
193 GNUNET_SCHEDULER_add_now (cleanup, NULL);
194 ret = 0;
195 return;
196 }
197}
198
199
200/**
201 * @brief Signature of a callback function that is called after a did has been removed
202 */
203typedef void
204(*remove_did_document_callback) (void *cls);
205
206/**
207 * @brief A Structure containing a cont and cls. Can be passed as a cls to a callback function
208 *
209 */
210struct Event
211{
212 remove_did_document_callback cont;
213 void *cls;
214};
215
216/**
217 * @brief Implements the GNUNET_NAMESTORE_ContinuationWithStatus
218 * Calls the callback function and cls in the event struct
219 *
220 * @param cls closure containing the event struct
221 * @param success
222 * @param emgs
223 */
224static void
225remove_did_document_namestore_cb (void *cls, enum GNUNET_ErrorCode ec)
226{
227 struct Event *event;
228
229 if (GNUNET_EC_NONE == ec)
230 {
231 event = (struct Event *) cls;
232
233 if (event->cont != NULL)
234 {
235 event->cont (event->cls);
236 free (event);
237 }
238 else
239 {
240 free (event);
241 GNUNET_SCHEDULER_add_now (cleanup, NULL);
242 ret = 0;
243 return;
244 }
245 }
246 else
247 {
248 printf ("Something went wrong when deleting the DID Document\n");
249
250 printf ("%s\n", GNUNET_ErrorCode_get_hint (ec));
251
252 GNUNET_SCHEDULER_add_now (cleanup, NULL);
253 ret = 0;
254 return;
255 }
256}
257
258
259/**
260 * @brief Callback called after the ego has been locked up
261 *
262 * @param cls closure
263 * @param ego the ego returned by the identity service
264 */
265static void
266remove_did_document_ego_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
267{
268 const struct GNUNET_CRYPTO_PrivateKey *skey =
269 GNUNET_IDENTITY_ego_get_private_key (ego);
270
271 GNUNET_NAMESTORE_record_set_store (namestore_handle,
272 skey,
273 GNUNET_GNS_EMPTY_LABEL_AT,
274 0,
275 NULL,
276 &remove_did_document_namestore_cb,
277 cls);
278}
279
280
281/**
282 * @brief Remove a DID Document
283 */
284static void
285remove_did_document (remove_did_document_callback cont, void *cls)
286{
287 struct Event *event;
288
289 if (egoname == NULL)
290 {
291 printf ("Remove requieres an ego option\n");
292 GNUNET_SCHEDULER_add_now (cleanup, NULL);
293 ret = 1;
294 return;
295 }
296 else
297 {
298 event = malloc (sizeof(*event));
299 event->cont = cont;
300 event->cls = cls;
301
302 GNUNET_IDENTITY_ego_lookup (my_cfg,
303 egoname,
304 &remove_did_document_ego_lookup_cb,
305 (void *) event);
306 }
307}
308
309
310// Needed because create_did_ego_lookup_cb() and
311// create_did_ego_create_cb() can call each other
312static void create_did_ego_lockup_cb ();
313
314/**
315 * @brief Create a DID(-Document). Called after DID has been created
316 * Prints status and the DID.
317 *
318 */
319static void
320create_did_cb (enum GNUNET_GenericReturnValue status, void *cls)
321{
322 if (GNUNET_OK == status)
323 {
324 printf ("DID has been created.\n%s\n", (char *) cls);
325 free (cls);
326 ret = 0;
327 }
328 else
329 {
330 printf ("An error occured while creating the DID.\n");
331 ret = 1;
332 }
333
334 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
335 return;
336}
337
338
339/**
340 * @brief Create a DID(-Document) - Called after a new Identity has been created.
341 */
342static void
343create_did_ego_create_cb (void *cls,
344 const struct GNUNET_CRYPTO_PrivateKey *pk,
345 enum GNUNET_ErrorCode ec)
346{
347 if (GNUNET_EC_NONE != ec)
348 {
349 printf ("%s\n", GNUNET_ErrorCode_get_hint (ec));
350 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
351 ret = 1;
352 return;
353 }
354
355 GNUNET_IDENTITY_ego_lookup (my_cfg,
356 egoname,
357 &create_did_ego_lockup_cb,
358 NULL);
359}
360
361
362/**
363 * @brief Create a DID(-Document). Called after ego lookup
364 *
365 */
366static void
367create_did_ego_lockup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
368{
369 if (ego == NULL)
370 {
371 // If Ego was not found. Create new one first
372 printf ("Ego was not found. Creating new one.\n");
373 GNUNET_IDENTITY_create (identity_handle,
374 egoname,
375 NULL,
376 GNUNET_PUBLIC_KEY_TYPE_EDDSA,
377 &create_did_ego_create_cb,
378 egoname);
379 }
380 else
381 {
382 char *did = DID_identity_to_did (ego);
383 void *cls = malloc (strlen (did) + 1);
384 struct GNUNET_TIME_Relative expire_relative;
385
386 if (expire == NULL)
387 {
388 GNUNET_STRINGS_fancy_time_to_relative (
389 DID_DOCUMENT_DEFAULT_EXPIRATION_TIME, &expire_relative);
390 }
391 else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (expire,
392 &
393 expire_relative))
394 {
395 printf ("Failed to read given expiration time\n");
396 GNUNET_SCHEDULER_add_now (cleanup, NULL);
397 ret = 1;
398 return;
399 }
400
401 strcpy (cls, did);
402 // TODO: Add DID_document argument
403 if (GNUNET_OK != DID_create (ego,
404 NULL,
405 &expire_relative,
406 namestore_handle,
407 create_did_cb,
408 cls))
409 {
410 printf ("An error occured while creating the DID.\n");
411 ret = 1;
412 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
413 return;
414 }
415 }
416}
417
418
419/**
420 * @brief Create a DID(-Document).
421 *
422 */
423static void
424create_did ()
425{
426 // Ego name to be set
427 if (egoname == NULL)
428 {
429 printf ("Set the Ego argument to create a new DID(-Document)\n");
430 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
431 ret = 1;
432 return;
433 }
434
435 GNUNET_IDENTITY_ego_lookup (my_cfg,
436 egoname,
437 &create_did_ego_lockup_cb,
438 NULL);
439}
440
441
442/**
443 * @brief Replace a DID Docuemnt. Callback function after ego lockup
444 *
445 * @param cls
446 * @param ego
447 */
448static void
449replace_did_document_ego_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
450{
451 // create_did_store (didd, ego);
452}
453
454
455/**
456 * @brief Replace a DID Document. Callback functiona after remove
457 *
458 * @param cls
459 */
460static void
461replace_did_document_remove_cb (void *cls)
462{
463 GNUNET_IDENTITY_ego_lookup (my_cfg,
464 egoname,
465 &replace_did_document_ego_lookup_cb,
466 NULL);
467}
468
469
470/**
471 * @brief Replace a DID Docuemnt
472 *
473 */
474static void
475replace_did_document ()
476{
477 if ((didd != NULL) && (expire != NULL))
478 {
479 remove_did_document (&replace_did_document_remove_cb, NULL);
480 }
481 else
482 {
483 printf (
484 "Set the DID Document and expiration time argument to replace the DID Document\n");
485 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
486 ret = 1;
487 return;
488 }
489}
490
491
492static void
493post_ego_iteration (void *cls)
494{
495 // TODO: Check that only one argument is set
496
497 if (1 == replace)
498 {
499 replace_did_document ();
500 }
501 else if (1 == get)
502 {
503 resolve_did ();
504 }
505 else if (1 == remove_did)
506 {
507 remove_did_document (NULL, NULL);
508 }
509 else if (1 == create)
510 {
511 create_did ();
512 }
513 else
514 {
515 // No Argument found
516 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
517 return;
518 }
519}
520
521
522static void
523process_dids (void *cls, struct GNUNET_IDENTITY_Ego *ego,
524 void **ctx, const char*name)
525{
526 char *did_str;
527
528 if (ego == NULL)
529 {
530 if (1 == ego_exists)
531 {
532 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
533 return;
534 }
535 GNUNET_SCHEDULER_add_now (&post_ego_iteration, NULL);
536 return;
537 }
538
539 if (1 == show_all)
540 {
541 did_str = DID_identity_to_did (ego);
542 printf ("%s:\n\t%s\n", name, did_str);
543 GNUNET_free (did_str);
544 return;
545 }
546 if (1 == show)
547 {
548 if (0 == strncmp (name, egoname, strlen (egoname)))
549 {
550 did_str = DID_identity_to_did (ego);
551 printf ("%s:\n\t%s\n", name, did_str);
552 GNUNET_free (did_str);
553 return;
554 }
555 }
556}
557
558
559static void
560run (void *cls,
561 char *const *args,
562 const char *cfgfile,
563 const struct GNUNET_CONFIGURATION_Handle *c)
564{
565 gns_handle = GNUNET_GNS_connect (c);
566 namestore_handle = GNUNET_NAMESTORE_connect (c);
567 my_cfg = c;
568
569 // check if GNS_handle could connect
570 if (gns_handle == NULL)
571 {
572 ret = 1;
573 return;
574 }
575
576 // check if NAMESTORE_handle could connect
577 if (namestore_handle == NULL)
578 {
579 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
580 ret = 1;
581 return;
582 }
583
584 identity_handle = GNUNET_IDENTITY_connect (c, &process_dids, NULL);
585 if (identity_handle == NULL)
586 {
587 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
588 ret = 1;
589 return;
590 }
591}
592
593
594int
595main (int argc, char *const argv[])
596{
597 struct GNUNET_GETOPT_CommandLineOption options[] = {
598 GNUNET_GETOPT_option_flag ('C',
599 "create",
600 gettext_noop (
601 "Create a DID Document and display its DID"),
602 &create),
603 GNUNET_GETOPT_option_flag ('g',
604 "get",
605 gettext_noop (
606 "Get the DID Document associated with the given DID"),
607 &get),
608 GNUNET_GETOPT_option_flag ('r',
609 "remove",
610 gettext_noop (
611 "Remove the DID"),
612 &remove_did),
613 GNUNET_GETOPT_option_flag ('R',
614 "replace",
615 gettext_noop ("Replace the DID Document."),
616 &replace),
617 GNUNET_GETOPT_option_flag ('s',
618 "show",
619 gettext_noop ("Show the DID for a given ego"),
620 &show),
621 GNUNET_GETOPT_option_flag ('A',
622 "show-all",
623 gettext_noop ("Show egos with DIDs"),
624 &show_all),
625 GNUNET_GETOPT_option_string ('d',
626 "did",
627 "DID",
628 gettext_noop (
629 "The Decentralized Identity (DID)"),
630 &did),
631 GNUNET_GETOPT_option_string ('D',
632 "did-document",
633 "JSON",
634 gettext_noop (
635 "The DID Document to store in GNUNET"),
636 &didd),
637 GNUNET_GETOPT_option_string ('e',
638 "ego",
639 "EGO",
640 gettext_noop ("The name of the EGO"),
641 &egoname),
642 GNUNET_GETOPT_option_string ('t',
643 "expiration-time",
644 "TIME",
645 gettext_noop (
646 "The time until the DID Document is going to expire (e.g. 5d)"),
647 &expire),
648 GNUNET_GETOPT_OPTION_END
649 };
650
651 if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
652 argv,
653 "gnunet-did",
654 "Manage Decentralized Identities (DIDs)",
655 options,
656 &run,
657 NULL))
658 return 1;
659 else
660 return ret;
661}
diff --git a/src/cli/reclaim/gnunet-reclaim.c b/src/cli/reclaim/gnunet-reclaim.c
new file mode 100644
index 000000000..94bceb8da
--- /dev/null
+++ b/src/cli/reclaim/gnunet-reclaim.c
@@ -0,0 +1,943 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-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 * @author Martin Schanzenbach
22 * @file src/reclaim/gnunet-reclaim.c
23 * @brief Identity Provider utility
24 *
25 */
26#include "platform.h"
27#include <inttypes.h>
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet_identity_service.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_reclaim_service.h"
34#include "gnunet_signatures.h"
35/**
36 * return value
37 */
38static int ret;
39
40/**
41 * List attribute flag
42 */
43static int list;
44
45/**
46 * List credentials flag
47 */
48static int list_credentials;
49
50/**
51 * Credential ID string
52 */
53static char *credential_id;
54
55/**
56 * The expected RP URI
57 */
58static char *ex_rp_uri;
59
60/**
61 * Credential ID
62 */
63static struct GNUNET_RECLAIM_Identifier credential;
64
65/**
66 * Credential name
67 */
68static char *credential_name;
69
70/**
71 * Credential type
72 */
73static char *credential_type;
74
75/**
76 * Credential exists
77 */
78static int credential_exists;
79
80/**
81 * Relying party
82 */
83static char *rp;
84
85/**
86 * The attribute
87 */
88static char *attr_name;
89
90/**
91 * Attribute value
92 */
93static char *attr_value;
94
95/**
96 * Attributes to issue
97 */
98static char *issue_attrs;
99
100/**
101 * Ticket to consume
102 */
103static char *consume_ticket;
104
105/**
106 * Attribute type
107 */
108static char *type_str;
109
110/**
111 * Ticket to revoke
112 */
113static char *revoke_ticket;
114
115/**
116 * Ticket listing
117 */
118static int list_tickets;
119
120/**
121 * Ego name
122 */
123static char *ego_name;
124
125/**
126 * Identity handle
127 */
128static struct GNUNET_IDENTITY_Handle *identity_handle;
129
130/**
131 * reclaim handle
132 */
133static struct GNUNET_RECLAIM_Handle *reclaim_handle;
134
135/**
136 * reclaim operation
137 */
138static struct GNUNET_RECLAIM_Operation *reclaim_op;
139
140/**
141 * Attribute iterator
142 */
143static struct GNUNET_RECLAIM_AttributeIterator *attr_iterator;
144
145/**
146 * Credential iterator
147 */
148static struct GNUNET_RECLAIM_CredentialIterator *cred_iterator;
149
150
151/**
152 * Ticket iterator
153 */
154static struct GNUNET_RECLAIM_TicketIterator *ticket_iterator;
155
156
157/**
158 * ego private key
159 */
160static const struct GNUNET_CRYPTO_PrivateKey *pkey;
161
162/**
163 * Ticket to consume
164 */
165static struct GNUNET_RECLAIM_Ticket ticket;
166
167/**
168 * Attribute list
169 */
170static struct GNUNET_RECLAIM_AttributeList *attr_list;
171
172/**
173 * Attribute expiration interval
174 */
175static struct GNUNET_TIME_Relative exp_interval;
176
177/**
178 * Timeout task
179 */
180static struct GNUNET_SCHEDULER_Task *timeout;
181
182/**
183 * Cleanup task
184 */
185static struct GNUNET_SCHEDULER_Task *cleanup_task;
186
187/**
188 * Claim to store
189 */
190struct GNUNET_RECLAIM_Attribute *claim;
191
192/**
193 * Claim to delete
194 */
195static char *attr_delete;
196
197/**
198 * Claim object to delete
199 */
200static struct GNUNET_RECLAIM_Attribute *attr_to_delete;
201
202static void
203do_cleanup (void *cls)
204{
205 cleanup_task = NULL;
206 if (NULL != timeout)
207 GNUNET_SCHEDULER_cancel (timeout);
208 if (NULL != reclaim_op)
209 GNUNET_RECLAIM_cancel (reclaim_op);
210 if (NULL != attr_iterator)
211 GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
212 if (NULL != cred_iterator)
213 GNUNET_RECLAIM_get_credentials_stop (cred_iterator);
214 if (NULL != ticket_iterator)
215 GNUNET_RECLAIM_ticket_iteration_stop (ticket_iterator);
216 if (NULL != reclaim_handle)
217 GNUNET_RECLAIM_disconnect (reclaim_handle);
218 if (NULL != identity_handle)
219 GNUNET_IDENTITY_disconnect (identity_handle);
220 if (NULL != attr_list)
221 {
222 GNUNET_RECLAIM_attribute_list_destroy (attr_list);
223 attr_list = NULL;
224 }
225 if (NULL != attr_to_delete)
226 GNUNET_free (attr_to_delete);
227 if (NULL == credential_type)
228 GNUNET_free (credential_type);
229}
230
231
232static void
233ticket_issue_cb (void *cls,
234 const struct GNUNET_RECLAIM_Ticket *ticket,
235 const struct GNUNET_RECLAIM_PresentationList *presentations)
236{
237 reclaim_op = NULL;
238 if (NULL != ticket)
239 {
240 printf ("%s\n", ticket->gns_name);
241 }
242 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
243}
244
245
246static void
247store_cont (void *cls, int32_t success, const char *emsg)
248{
249 reclaim_op = NULL;
250 if (GNUNET_SYSERR == success)
251 {
252 fprintf (stderr, "%s\n", emsg);
253 }
254 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
255}
256
257
258static void
259process_attrs (void *cls,
260 const struct GNUNET_CRYPTO_PublicKey *identity,
261 const struct GNUNET_RECLAIM_Attribute *attr,
262 const struct GNUNET_RECLAIM_Presentation *presentation)
263{
264 char *value_str;
265 char *id;
266 const char *attr_type;
267
268 if (NULL == identity)
269 {
270 reclaim_op = NULL;
271 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
272 return;
273 }
274 if (NULL == attr)
275 {
276 ret = 1;
277 return;
278 }
279 attr_type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
280 id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
281 value_str = NULL;
282 if (NULL == presentation)
283 {
284 value_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
285 attr->data,
286 attr->data_size);
287 }
288 else
289 {
290 struct GNUNET_RECLAIM_AttributeListEntry *ale;
291 struct GNUNET_RECLAIM_AttributeList *al
292 = GNUNET_RECLAIM_presentation_get_attributes (presentation);
293
294 for (ale = al->list_head; NULL != ale; ale = ale->next)
295 {
296 if (0 != strncmp (attr->data, ale->attribute->name, attr->data_size))
297 continue;
298 value_str
299 = GNUNET_RECLAIM_attribute_value_to_string (ale->attribute->type,
300 ale->attribute->data,
301 ale->attribute->data_size);
302 break;
303 }
304 }
305 fprintf (stdout,
306 "Name: %s; Value: %s (%s); Flag %u; ID: %s %s\n",
307 attr->name,
308 (NULL != value_str) ? value_str : "???",
309 attr_type,
310 attr->flag,
311 id,
312 (NULL == presentation) ? "" : "(ATTESTED)");
313 GNUNET_free (value_str);
314 GNUNET_free (id);
315}
316
317
318static void
319ticket_iter_err (void *cls)
320{
321 ticket_iterator = NULL;
322 fprintf (stderr, "Failed to iterate over tickets\n");
323 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
324}
325
326
327static void
328ticket_iter_fin (void *cls)
329{
330 ticket_iterator = NULL;
331 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
332}
333
334
335static void
336ticket_iter (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket, const char* rp_uri)
337{
338 fprintf (stdout, "Ticket: %s | RP URI: %s\n", ticket->gns_name, rp_uri);
339 GNUNET_RECLAIM_ticket_iteration_next (ticket_iterator);
340}
341
342
343static void
344iter_error (void *cls)
345{
346 attr_iterator = NULL;
347 cred_iterator = NULL;
348 fprintf (stderr, "Failed\n");
349
350 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
351}
352
353
354static void
355timeout_task (void *cls)
356{
357 timeout = NULL;
358 ret = 1;
359 fprintf (stderr, "Timeout\n");
360 if (NULL == cleanup_task)
361 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
362}
363
364
365static void
366process_rvk (void *cls, int success, const char *msg)
367{
368 reclaim_op = NULL;
369 if (GNUNET_OK != success)
370 {
371 fprintf (stderr, "Revocation failed.\n");
372 ret = 1;
373 }
374 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
375}
376
377
378static void
379process_delete (void *cls, int success, const char *msg)
380{
381 reclaim_op = NULL;
382 if (GNUNET_OK != success)
383 {
384 fprintf (stderr, "Deletion failed.\n");
385 ret = 1;
386 }
387 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
388}
389
390
391static void
392iter_finished (void *cls)
393{
394 struct GNUNET_RECLAIM_AttributeListEntry *le;
395 char *attrs_tmp;
396 char *attr_str;
397 char *data;
398 size_t data_size;
399 int type;
400
401 attr_iterator = NULL;
402 if (list)
403 {
404 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
405 return;
406 }
407
408 if (issue_attrs)
409 {
410 attrs_tmp = GNUNET_strdup (issue_attrs);
411 attr_str = strtok (attrs_tmp, ",");
412 while (NULL != attr_str)
413 {
414 le = attr_list->list_head;
415 while (le)
416 {
417 if (0 == strcasecmp (attr_str, le->attribute->name))
418 break;
419
420 le = le->next;
421 }
422
423 if (! le)
424 {
425 fprintf (stdout, "No such attribute ``%s''\n", attr_str);
426 break;
427 }
428 attr_str = strtok (NULL, ",");
429 }
430 GNUNET_free (attrs_tmp);
431 if (NULL != attr_str)
432 {
433 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
434 return;
435 }
436 if (NULL == ex_rp_uri)
437 {
438 fprintf (stdout, "No RP URI provided\n");
439 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
440 return;
441 }
442 reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
443 pkey,
444 ex_rp_uri,
445 attr_list,
446 &ticket_issue_cb,
447 NULL);
448 return;
449 }
450 if (consume_ticket)
451 {
452 if (NULL == ex_rp_uri)
453 {
454 fprintf (stderr, "Expected an RP URI to consume ticket\n");
455 GNUNET_SCHEDULER_add_now(&do_cleanup, NULL);
456 return;
457 }
458 reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
459 &ticket,
460 ex_rp_uri,
461 &process_attrs,
462 NULL);
463 timeout = GNUNET_SCHEDULER_add_delayed (
464 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
465 &timeout_task,
466 NULL);
467 return;
468 }
469 if (revoke_ticket)
470 {
471 reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
472 pkey,
473 &ticket,
474 &process_rvk,
475 NULL);
476 return;
477 }
478 if (attr_delete)
479 {
480 if (NULL == attr_to_delete)
481 {
482 fprintf (stdout, "No such attribute ``%s''\n", attr_delete);
483 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
484 return;
485 }
486 reclaim_op = GNUNET_RECLAIM_attribute_delete (reclaim_handle,
487 pkey,
488 attr_to_delete,
489 &process_delete,
490 NULL);
491 return;
492 }
493 if (attr_name)
494 {
495 if (NULL == type_str)
496 type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
497 else
498 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
499
500 GNUNET_assert (GNUNET_SYSERR !=
501 GNUNET_RECLAIM_attribute_string_to_value (type,
502 attr_value,
503 (void **) &data,
504 &data_size));
505 if (NULL != claim)
506 {
507 claim->type = type;
508 claim->data = data;
509 claim->data_size = data_size;
510 }
511 else
512 {
513 claim =
514 GNUNET_RECLAIM_attribute_new (attr_name, NULL, type, data, data_size);
515 }
516 if (NULL != credential_id)
517 {
518 claim->credential = credential;
519 }
520 reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
521 pkey,
522 claim,
523 &exp_interval,
524 &store_cont,
525 NULL);
526 GNUNET_free (data);
527 GNUNET_free (claim);
528 return;
529 }
530 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
531}
532
533
534static void
535iter_cb (void *cls,
536 const struct GNUNET_CRYPTO_PublicKey *identity,
537 const struct GNUNET_RECLAIM_Attribute *attr)
538{
539 struct GNUNET_RECLAIM_AttributeListEntry *le;
540 char *attrs_tmp;
541 char *attr_str;
542 char *label;
543 char *id;
544 const char *attr_type;
545
546 if ((NULL != attr_name) && (NULL == claim))
547 {
548 if (0 == strcasecmp (attr_name, attr->name))
549 {
550 claim = GNUNET_RECLAIM_attribute_new (attr->name,
551 &attr->credential,
552 attr->type,
553 attr->data,
554 attr->data_size);
555 claim->id = attr->id;
556 }
557 }
558 else if (issue_attrs)
559 {
560 attrs_tmp = GNUNET_strdup (issue_attrs);
561 attr_str = strtok (attrs_tmp, ",");
562 while (NULL != attr_str)
563 {
564 if (0 != strcasecmp (attr_str, attr->name))
565 {
566 attr_str = strtok (NULL, ",");
567 continue;
568 }
569 le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
570 le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
571 &attr->credential,
572 attr->type,
573 attr->data,
574 attr->data_size);
575 le->attribute->flag = attr->flag;
576 le->attribute->id = attr->id;
577 GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
578 attr_list->list_tail,
579 le);
580 break;
581 }
582 GNUNET_free (attrs_tmp);
583 }
584 else if (attr_delete && (NULL == attr_to_delete))
585 {
586 label = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
587 if (0 == strcasecmp (attr_delete, label))
588 {
589 attr_to_delete = GNUNET_RECLAIM_attribute_new (attr->name,
590 &attr->credential,
591 attr->type,
592 attr->data,
593 attr->data_size);
594 attr_to_delete->id = attr->id;
595 }
596 GNUNET_free (label);
597 }
598 else if (list)
599 {
600 attr_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
601 attr->data,
602 attr->data_size);
603 attr_type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
604 id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
605 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->credential))
606 {
607 fprintf (stdout,
608 "%s: ``%s'' (%s); ID: %s\n",
609 attr->name,
610 attr_str,
611 attr_type,
612 id);
613 }
614 else
615 {
616 char *cred_id =
617 GNUNET_STRINGS_data_to_string_alloc (&attr->credential,
618 sizeof(attr->credential));
619 fprintf (stdout,
620 "%s: ``%s'' in credential presentation `%s' (%s); ID: %s\n",
621 attr->name,
622 attr_str,
623 cred_id,
624 attr_type,
625 id);
626 GNUNET_free (cred_id);
627
628 }
629 GNUNET_free (id);
630 }
631 GNUNET_RECLAIM_get_attributes_next (attr_iterator);
632}
633
634
635static void
636cred_iter_finished (void *cls)
637{
638 cred_iterator = NULL;
639
640 // Add new credential
641 if ((NULL != credential_name) &&
642 (NULL != attr_value))
643 {
644 enum GNUNET_RECLAIM_CredentialType ctype =
645 GNUNET_RECLAIM_credential_typename_to_number (credential_type);
646 struct GNUNET_RECLAIM_Credential *credential =
647 GNUNET_RECLAIM_credential_new (credential_name,
648 ctype,
649 attr_value,
650 strlen (attr_value));
651 reclaim_op = GNUNET_RECLAIM_credential_store (reclaim_handle,
652 pkey,
653 credential,
654 &exp_interval,
655 store_cont,
656 NULL);
657 return;
658
659 }
660 if (list_credentials)
661 {
662 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
663 return;
664 }
665 attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
666 pkey,
667 &iter_error,
668 NULL,
669 &iter_cb,
670 NULL,
671 &iter_finished,
672 NULL);
673
674}
675
676
677static void
678cred_iter_cb (void *cls,
679 const struct GNUNET_CRYPTO_PublicKey *identity,
680 const struct GNUNET_RECLAIM_Credential *cred)
681{
682 char *cred_str;
683 char *attr_str;
684 char *id;
685 const char *cred_type;
686 struct GNUNET_RECLAIM_AttributeListEntry *ale;
687
688 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&credential,
689 &cred->id))
690 credential_exists = GNUNET_YES;
691 if (list_credentials)
692 {
693 cred_str = GNUNET_RECLAIM_credential_value_to_string (cred->type,
694 cred->data,
695 cred->data_size);
696 cred_type = GNUNET_RECLAIM_credential_number_to_typename (cred->type);
697 id = GNUNET_STRINGS_data_to_string_alloc (&cred->id, sizeof(cred->id));
698 fprintf (stdout,
699 "%s: ``%s'' (%s); ID: %s\n",
700 cred->name,
701 cred_str,
702 cred_type,
703 id);
704 struct GNUNET_RECLAIM_AttributeList *attrs =
705 GNUNET_RECLAIM_credential_get_attributes (cred);
706 if (NULL != attrs)
707 {
708 fprintf (stdout,
709 "\t Attributes:\n");
710 for (ale = attrs->list_head; NULL != ale; ale = ale->next)
711 {
712 attr_str = GNUNET_RECLAIM_attribute_value_to_string (
713 ale->attribute->type,
714 ale->attribute->data,
715 ale->attribute->data_size);
716 fprintf (stdout,
717 "\t %s: %s\n", ale->attribute->name, attr_str);
718 GNUNET_free (attr_str);
719 }
720 GNUNET_RECLAIM_attribute_list_destroy (attrs);
721 }
722 GNUNET_free (id);
723 }
724 GNUNET_RECLAIM_get_credentials_next (cred_iterator);
725}
726
727
728static void
729start_process ()
730{
731 if (NULL == pkey)
732 {
733 fprintf (stderr, "Ego %s not found\n", ego_name);
734 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
735 return;
736 }
737 if (NULL == credential_type)
738 credential_type = GNUNET_strdup ("JWT");
739 credential = GNUNET_RECLAIM_ID_ZERO;
740 if (NULL != credential_id)
741 GNUNET_STRINGS_string_to_data (credential_id,
742 strlen (credential_id),
743 &credential, sizeof(credential));
744 credential_exists = GNUNET_NO;
745 if (list_tickets)
746 {
747 ticket_iterator = GNUNET_RECLAIM_ticket_iteration_start (reclaim_handle,
748 pkey,
749 &ticket_iter_err,
750 NULL,
751 &ticket_iter,
752 NULL,
753 &ticket_iter_fin,
754 NULL);
755 return;
756 }
757
758 if (NULL != consume_ticket)
759 memcpy (ticket.gns_name, consume_ticket, strlen (consume_ticket) + 1);
760 if (NULL != revoke_ticket)
761 GNUNET_STRINGS_string_to_data (revoke_ticket,
762 strlen (revoke_ticket),
763 &ticket,
764 sizeof(struct GNUNET_RECLAIM_Ticket));
765
766 attr_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
767 claim = NULL;
768 cred_iterator = GNUNET_RECLAIM_get_credentials_start (reclaim_handle,
769 pkey,
770 &iter_error,
771 NULL,
772 &cred_iter_cb,
773 NULL,
774 &cred_iter_finished,
775 NULL);
776
777}
778
779
780static int init = GNUNET_YES;
781
782static void
783ego_cb (void *cls,
784 struct GNUNET_IDENTITY_Ego *ego,
785 void **ctx,
786 const char *name)
787{
788 if (NULL == name)
789 {
790 if (GNUNET_YES == init)
791 {
792 init = GNUNET_NO;
793 start_process ();
794 }
795 return;
796 }
797 if (0 != strcmp (name, ego_name))
798 return;
799 pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
800}
801
802
803static void
804run (void *cls,
805 char *const *args,
806 const char *cfgfile,
807 const struct GNUNET_CONFIGURATION_Handle *c)
808{
809 ret = 0;
810 if (NULL == ego_name)
811 {
812 ret = 1;
813 fprintf (stderr, _ ("Ego is required\n"));
814 return;
815 }
816
817 if ((NULL == attr_value) && (NULL != attr_name))
818 {
819 ret = 1;
820 fprintf (stderr, _ ("Attribute value missing!\n"));
821 return;
822 }
823
824 if ((NULL == rp) && (NULL != issue_attrs))
825 {
826 ret = 1;
827 fprintf (stderr, _ ("Requesting party key is required!\n"));
828 return;
829 }
830
831 reclaim_handle = GNUNET_RECLAIM_connect (c);
832 // Get Ego
833 identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, NULL);
834}
835
836
837int
838main (int argc, char *const argv[])
839{
840 exp_interval = GNUNET_TIME_UNIT_HOURS;
841 struct GNUNET_GETOPT_CommandLineOption options[] = {
842 GNUNET_GETOPT_option_string ('a',
843 "add",
844 "NAME",
845 gettext_noop (
846 "Add or update an attribute NAME"),
847 &attr_name),
848 GNUNET_GETOPT_option_string ('d',
849 "delete",
850 "ID",
851 gettext_noop ("Delete the attribute with ID"),
852 &attr_delete),
853 GNUNET_GETOPT_option_string ('V',
854 "value",
855 "VALUE",
856 gettext_noop ("The attribute VALUE"),
857 &attr_value),
858 GNUNET_GETOPT_option_string ('e',
859 "ego",
860 "EGO",
861 gettext_noop ("The EGO to use"),
862 &ego_name),
863 GNUNET_GETOPT_option_string ('r',
864 "rp",
865 "RP",
866 gettext_noop (
867 "Specify the relying party for issue"),
868 &rp),
869 GNUNET_GETOPT_option_string ('U',
870 "rpuri",
871 "RPURI",
872 gettext_noop (
873 "Specify the relying party URI for a ticket to consume"),
874 &ex_rp_uri),
875 GNUNET_GETOPT_option_flag ('D',
876 "dump",
877 gettext_noop ("List attributes for EGO"),
878 &list),
879 GNUNET_GETOPT_option_flag ('A',
880 "credentials",
881 gettext_noop ("List credentials for EGO"),
882 &list_credentials),
883 GNUNET_GETOPT_option_string ('I',
884 "credential-id",
885 "CREDENTIAL_ID",
886 gettext_noop (
887 "Credential to use for attribute"),
888 &credential_id),
889 GNUNET_GETOPT_option_string ('N',
890 "credential-name",
891 "NAME",
892 gettext_noop ("Credential name"),
893 &credential_name),
894 GNUNET_GETOPT_option_string ('i',
895 "issue",
896 "A1,A2,...",
897 gettext_noop (
898 "Issue a ticket for a set of attributes separated by comma"),
899 &issue_attrs),
900 GNUNET_GETOPT_option_string ('C',
901 "consume",
902 "TICKET",
903 gettext_noop ("Consume a ticket"),
904 &consume_ticket),
905 GNUNET_GETOPT_option_string ('R',
906 "revoke",
907 "TICKET",
908 gettext_noop ("Revoke a ticket"),
909 &revoke_ticket),
910 GNUNET_GETOPT_option_string ('t',
911 "type",
912 "TYPE",
913 gettext_noop ("Type of attribute"),
914 &type_str),
915 GNUNET_GETOPT_option_string ('u',
916 "credential-type",
917 "TYPE",
918 gettext_noop ("Type of credential"),
919 &credential_type),
920 GNUNET_GETOPT_option_flag ('T',
921 "tickets",
922 gettext_noop ("List tickets of ego"),
923 &list_tickets),
924 GNUNET_GETOPT_option_relative_time ('E',
925 "expiration",
926 "INTERVAL",
927 gettext_noop (
928 "Expiration interval of the attribute"),
929 &exp_interval),
930
931 GNUNET_GETOPT_OPTION_END
932 };
933 if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
934 argv,
935 "gnunet-reclaim",
936 _ ("re:claimID command line tool"),
937 options,
938 &run,
939 NULL))
940 return 1;
941 else
942 return ret;
943}
diff --git a/src/cli/reclaim/meson.build b/src/cli/reclaim/meson.build
new file mode 100644
index 000000000..53ce13edb
--- /dev/null
+++ b/src/cli/reclaim/meson.build
@@ -0,0 +1,22 @@
1executable ('gnunet-reclaim',
2 'gnunet-reclaim.c',
3 dependencies: [libgnunetreclaim_dep,
4 libgnunetidentity_dep,
5 libgnunetutil_dep],
6 include_directories: [incdir, configuration_inc],
7 install: true,
8 install_dir: get_option('bindir'))
9executable ('gnunet-did',
10 'gnunet-did.c',
11 dependencies: [libgnunetreclaim_dep,
12 libgnunetdid_dep,
13 libgnunetgns_dep,
14 libgnunetnamestore_dep,
15 libgnunetidentity_dep,
16 libgnunetutil_dep],
17 include_directories: [incdir,
18 configuration_inc,
19 include_directories ('../../service/reclaim')],
20 install: true,
21 install_dir: get_option('bindir'))
22
diff --git a/src/cli/reclaim/test_reclaim.conf b/src/cli/reclaim/test_reclaim.conf
new file mode 100644
index 000000000..a8d2c808a
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim.conf
@@ -0,0 +1,44 @@
1@INLINE@ test_reclaim_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-reclaim-peer-1/
5
6[dht]
7START_ON_DEMAND = YES
8
9[rest]
10START_ON_DEMAND = YES
11# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/restlog
12BASIC_AUTH_ENABLED = NO
13
14[transport]
15PLUGINS =
16
17[zonemaster]
18START_ON_DEMAND = YES
19IMMEDIATE_START = YES
20
21[reclaim]
22IMMEDIATE_START = YES
23START_ON_DEMAND = YES
24TICKET_REFRESH_INTERVAL = 1 h
25#PREFIX = valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=$GNUNET_TMP/idplog
26
27[gns]
28#PREFIX = valgrind --leak-check=full --track-origins=yes
29START_ON_DEMAND = YES
30AUTO_IMPORT_PKEY = YES
31MAX_PARALLEL_BACKGROUND_QUERIES = 10
32DEFAULT_LOOKUP_TIMEOUT = 15 s
33RECORD_PUT_INTERVAL = 1 h
34ZONE_PUBLISH_TIME_WINDOW = 1 h
35DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
36
37[reclaim-rest-plugin]
38expiration_time = 3600
39JWT_SECRET = secret
40OIDC_USERINFO_CONSUME_TIMEOUT = 5s
41OIDC_DIR = $GNUNET_DATA_HOME/oidc
42OIDC_CLIENT_HMAC_SECRET = secret
43OIDC_JSON_WEB_ALGORITHM = RS256
44ADDRESS = https://ui.reclaim/#/login
diff --git a/src/cli/reclaim/test_reclaim.sh b/src/cli/reclaim/test_reclaim.sh
new file mode 100755
index 000000000..da93b10f7
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim.sh
@@ -0,0 +1,31 @@
1#!/bin/sh
2#trap "gnunet-arm -e -c test_reclaim_lookup.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27gnunet-identity -C testego -c test_reclaim.conf
28valgrind gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
29gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
30gnunet-reclaim -e testego -D -c test_reclaim.conf
31gnunet-arm -e -c test_reclaim.conf
diff --git a/src/cli/reclaim/test_reclaim_attribute.sh b/src/cli/reclaim/test_reclaim_attribute.sh
new file mode 100755
index 000000000..17f7863d4
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim_attribute.sh
@@ -0,0 +1,40 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27#gnunet-arm -i rest -c test_reclaim.conf
28gnunet-identity -C testego -c test_reclaim.conf
29gnunet-identity -C rpego -c test_reclaim.conf
30TEST_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
31gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
32gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
33if test $? != 0
34then
35 echo "Failed."
36 exit 1
37fi
38
39#curl localhost:7776/reclaim/attributes/testego
40gnunet-arm -e -c test_reclaim.conf
diff --git a/src/cli/reclaim/test_reclaim_consume.sh b/src/cli/reclaim/test_reclaim_consume.sh
new file mode 100755
index 000000000..00076fbf8
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim_consume.sh
@@ -0,0 +1,51 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1>/dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27#gnunet-arm -i rest -c test_reclaim.conf
28gnunet-arm -I
29gnunet-identity -C testego -c test_reclaim.conf
30gnunet-identity -C rpego -c test_reclaim.conf
31SUBJECT_KEY=$(gnunet-identity -d -e rpego -q -c test_reclaim.conf)
32TEST_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
33gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
34gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
35TICKET=$(gnunet-reclaim -e testego -U "urn:gns:$TEST_KEY" -i "email,name" -r $SUBJECT_KEY -c test_reclaim.conf | awk '{print $1}')
36echo "Ticket: $TICKET"
37gnunet-gns -u $TICKET -c test_reclaim.conf
38gnunet-namestore -z testego -D -c test_reclaim.conf
39gnunet-identity -d -c test_reclaim.conf
40sleep 1
41gnunet-reclaim -e rpego -U "urn:gns:$TEST_KEY" -C $TICKET -c test_reclaim.conf
42
43RES=$?
44gnunet-identity -D testego -c test_reclaim.conf
45gnunet-identity -D rpego -c test_reclaim.conf
46gnunet-arm -e -c test_reclaim.conf
47if test $RES != 0
48then
49 echo "Failed."
50fi
51
diff --git a/src/cli/reclaim/test_reclaim_defaults.conf b/src/cli/reclaim/test_reclaim_defaults.conf
new file mode 100644
index 000000000..02372563d
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim_defaults.conf
@@ -0,0 +1,24 @@
1@INLINE@ ../../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-idp-testing/
5
6[namestore-sqlite]
7FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
8
9[namecache-sqlite]
10FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db
11
12[identity]
13# Directory where we store information about our egos
14EGODIR = $GNUNET_TEST_HOME/identity/egos/
15
16[dhtcache]
17DATABASE = heap
18
19[transport]
20PLUGINS = tcp
21
22[transport-tcp]
23BINDTO = 127.0.0.1
24
diff --git a/src/cli/reclaim/test_reclaim_issue.sh b/src/cli/reclaim/test_reclaim_issue.sh
new file mode 100755
index 000000000..39e614d19
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim_issue.sh
@@ -0,0 +1,42 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27#gnunet-arm -i rest -c test_reclaim.conf
28gnunet-identity -C testego -c test_reclaim.conf
29gnunet-identity -C rpego -c test_reclaim.conf
30SUBJECT_KEY=$(gnunet-identity -d -e rpego -q -c test_reclaim.conf)
31TEST_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
32gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
33gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
34#gnunet-reclaim -e testego -D -c test_reclaim.conf
35gnunet-reclaim -e testego -u "urn:gns:$TEST_KEY" -i "email,name" -r $SUBJECT_KEY -c test_reclaim.conf > /dev/null 2>&1
36if test $? != 0
37then
38 echo "Failed."
39 exit 1
40fi
41#curl http://localhost:7776/reclaim/attributes/testego
42gnunet-arm -e -c test_reclaim.conf
diff --git a/src/cli/reclaim/test_reclaim_oidc.sh b/src/cli/reclaim/test_reclaim_oidc.sh
new file mode 100755
index 000000000..cdea61a03
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim_oidc.sh
@@ -0,0 +1,57 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1>/dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19
20RES=0
21TEST_ATTR="test"
22REDIRECT_URI="https://example.gns.alt/my_cb"
23SCOPE="\"openid email name\""
24gnunet-arm -s -c test_reclaim.conf
25gnunet-arm -i rest -c test_reclaim.conf
26gnunet-arm -I
27gnunet-identity -C testego -c test_reclaim.conf
28gnunet-identity -C rpego -c test_reclaim.conf
29TEST_KEY=$(gnunet-identity -d -e rpego -q -c test_reclaim.conf)
30SUBJECT_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
31gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
32gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
33
34# Register client
35gnunet-namestore -z rpego -a -n @ -t RECLAIM_OIDC_CLIENT -V "My RP" -e 1d -p -c test_reclaim.conf
36gnunet-namestore -z rpego -a -n @ -t RECLAIM_OIDC_REDIRECT -V $REDIRECT_URI -e 1d -p -c test_reclaim.conf
37
38gnunet-gns -u @.$TEST_KEY -t RECLAIM_OIDC_REDIRECT -c test_reclaim.conf
39curl -v -X POST -H -v "http://localhost:7776/openid/login" --data "{\"identity\": \"$SUBJECT_KEY\"}"
40
41PKCE_CHALLENGE=$(echo -n secret | openssl dgst -binary -sha256 | openssl base64 | sed 's/\=//g' | sed 's/+/-/g' | sed 's/\//_/g')
42
43CODE=$(curl -H "Cookie: Identity=$SUBJECT_KEY" "http://localhost:7776/openid/authorize?client_id=$TEST_KEY&response_type=code&redirect_uri=$REDIRECT_URI&scope=openid&claims=%7B%22userinfo%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%20%20%20%20%3A%20true%7D%7D%2C%22id_token%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%3A%20true%7D%7D%7D&state=xyz&code_challenge=$PKCE_CHALLENGE&code_challenge_method=S256" \
44 -sS -D - -o /dev/null | grep "Location: " | cut -d" " -f2 | cut -d"?" -f2 | cut -d"&" -f1 | cut -d"=" -f2)
45
46echo "Code: $CODE"
47
48curl -v -X POST -u$TEST_KEY:"secret" "http://localhost:7776/openid/token?client_id=$TEST_KEY&response_type=code&redirect_uri=$REDIRECT_URI&scope=openid&claims=%7B%22userinfo%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%20%20%20%20%3A%20true%7D%7D%2C%22id_token%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%3A%20true%7D%7D%7D&state=xyz&grant_type=authorization_code&code=$CODE&code_verifier=secret"
49
50gnunet-identity -D testego -c test_reclaim.conf
51gnunet-identity -D rpego -c test_reclaim.conf
52gnunet-arm -e -c test_reclaim.conf
53if test $RES != 0
54then
55 echo "Failed."
56fi
57
diff --git a/src/cli/reclaim/test_reclaim_revoke.sh b/src/cli/reclaim/test_reclaim_revoke.sh
new file mode 100755
index 000000000..da091a1ee
--- /dev/null
+++ b/src/cli/reclaim/test_reclaim_revoke.sh
@@ -0,0 +1,65 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout >/dev/null 2&>1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf >/dev/null 2&>1
27gnunet-identity -C alice -c test_reclaim.conf
28gnunet-identity -C bob -c test_reclaim.conf
29gnunet-identity -C eve -c test_reclaim.conf
30ALICE_KEY=$(gnunet-identity -d -e alice -q -c test_reclaim.conf)
31BOB_KEY=$(gnunet-identity -d -e bob -q -c test_reclaim.conf)
32EVE_KEY=$(gnunet-identity -d -e eve -q -c test_reclaim.conf)
33gnunet-reclaim -e alice -E 15s -a email -V john@doe.gnu -c test_reclaim.conf
34gnunet-reclaim -e alice -E 15s -a name -V John -c test_reclaim.conf
35TICKET_BOB=$(gnunet-reclaim -e alice -i "email,name" -r $BOB_KEY -c test_reclaim.conf | awk '{print $1}')
36#gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf
37TICKET_EVE=$(gnunet-reclaim -e alice -i "email" -r $EVE_KEY -c test_reclaim.conf | awk '{print $1}')
38gnunet-namestore -z alice -D
39echo "Revoking $TICKET"
40gnunet-reclaim -e alice -R $TICKET_EVE -c test_reclaim.conf
41gnunet-namestore -z alice -D
42sleep 16
43echo "Consuming $TICKET"
44
45gnunet-reclaim -e eve -C $TICKET_EVE -c test_reclaim.conf
46if test $? = 0
47then
48 echo "Eve can still resolve attributes..."
49 gnunet-arm -e -c test_reclaim.conf
50 exit 1
51fi
52
53gnunet-arm -e -c test_reclaim.conf
54gnunet-arm -s -c test_reclaim.conf >/dev/null 2&>1
55
56gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf
57#gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf >/dev/null 2&>1
58if test $? != 0
59then
60 echo "Bob cannot resolve attributes..."
61 gnunet-arm -e -c test_reclaim.conf
62 exit 1
63fi
64
65gnunet-arm -e -c test_reclaim.conf
diff --git a/src/cli/revocation/Makefile.am b/src/cli/revocation/Makefile.am
new file mode 100644
index 000000000..ffd76effa
--- /dev/null
+++ b/src/cli/revocation/Makefile.am
@@ -0,0 +1,52 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11pkgcfgdir= $(pkgdatadir)/config.d/
12
13libexecdir= $(pkglibdir)/libexec/
14
15bin_PROGRAMS = \
16 gnunet-revocation
17
18gnunet_revocation_SOURCES = \
19 gnunet-revocation.c
20gnunet_revocation_LDADD = \
21 $(top_builddir)/src/service/revocation/libgnunetrevocation.la \
22 $(top_builddir)/src/service/identity/libgnunetidentity.la \
23 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
24 $(top_builddir)/src/lib/util/libgnunetutil.la \
25 $(GN_LIBINTL)
26
27gnunet_revocation_tvg_SOURCES = \
28 gnunet-revocation-tvg.c
29gnunet_revocation_tvg_LDADD = \
30 $(top_builddir)/src/service/revocation/libgnunetrevocation.la \
31 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
32 $(top_builddir)/src/lib/util/libgnunetutil.la \
33 $(GN_LIBINTL)
34
35noinst_PROGRAMS = \
36 gnunet-revocation-tvg
37
38check_SCRIPTS = \
39 #test_local_revocation.py
40
41if ENABLE_TEST_RUN
42 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
43 TESTS = \
44 $(check_SCRIPTS) \
45 $(check_PROGRAMS)
46endif
47
48test_local_revocation.py: test_local_revocation.py.in Makefile
49 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/test_local_revocation.py.in > test_local_revocation.py
50 chmod +x test_local_revocation.py
51
52EXTRA_DIST = test_local_revocation.py.in
diff --git a/src/cli/revocation/gnunet-revocation-tvg.c b/src/cli/revocation/gnunet-revocation-tvg.c
new file mode 100644
index 000000000..5c2bfbe45
--- /dev/null
+++ b/src/cli/revocation/gnunet-revocation-tvg.c
@@ -0,0 +1,230 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 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 util/gnunet-revocation-tvg.c
23 * @brief Generate test vectors for revocation.
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include "gnunet_revocation_service.h"
30#include "gnunet_testing_lib.h"
31// FIXME try to avoid this include somehow
32#include "../../lib/gnsrecord/gnsrecord_crypto.h"
33#include <inttypes.h>
34
35#define TEST_EPOCHS 2
36#define TEST_DIFFICULTY 5
37
38static char*d_pkey =
39 "6fea32c05af58bfa979553d188605fd57d8bf9cc263b78d5f7478c07b998ed70";
40
41static char *d_edkey =
42 "5af7020ee19160328832352bbc6a68a8d71a7cbe1b929969a7c66d415a0d8f65";
43
44int
45parsehex (char *src, char *dst, size_t dstlen, int invert)
46{
47 char *line = src;
48 char *data = line;
49 int off;
50 int read_byte;
51 int data_len = 0;
52
53 while (sscanf (data, " %02x%n", &read_byte, &off) == 1)
54 {
55 if (invert)
56 dst[dstlen - 1 - data_len++] = read_byte;
57 else
58 dst[data_len++] = read_byte;
59 data += off;
60 }
61 return data_len;
62}
63
64
65static void
66print_bytes_ (void *buf,
67 size_t buf_len,
68 int fold,
69 int in_be)
70{
71 int i;
72
73 for (i = 0; i < buf_len; i++)
74 {
75 if (0 != i)
76 {
77 if ((0 != fold) && (i % fold == 0))
78 printf ("\n ");
79 else
80 printf (" ");
81 }
82 else
83 {
84 printf (" ");
85 }
86 if (in_be)
87 printf ("%02x", ((unsigned char*) buf)[buf_len - 1 - i]);
88 else
89 printf ("%02x", ((unsigned char*) buf)[i]);
90 }
91 printf ("\n");
92}
93
94
95static void
96print_bytes (void *buf,
97 size_t buf_len,
98 int fold)
99{
100 print_bytes_ (buf, buf_len, fold, 0);
101}
102
103
104static void
105run_with_key (struct GNUNET_CRYPTO_PrivateKey *id_priv)
106{
107 struct GNUNET_CRYPTO_PublicKey id_pub;
108 struct GNUNET_GNSRECORD_PowP *pow;
109 struct GNUNET_GNSRECORD_PowCalculationHandle *ph;
110 struct GNUNET_TIME_Relative exp;
111 char ztld[128];
112 ssize_t key_len;
113
114 GNUNET_CRYPTO_key_get_public (id_priv,
115 &id_pub);
116 GNUNET_STRINGS_data_to_string (&id_pub,
117 GNUNET_CRYPTO_public_key_get_length (
118 &id_pub),
119 ztld,
120 sizeof (ztld));
121 fprintf (stdout, "\n");
122 fprintf (stdout, "Zone identifier (ztype|zkey):\n");
123 key_len = GNUNET_CRYPTO_public_key_get_length (&id_pub);
124 GNUNET_assert (0 < key_len);
125 print_bytes (&id_pub, key_len, 8);
126 fprintf (stdout, "\n");
127 fprintf (stdout, "Encoded zone identifier (zkl = zTLD):\n");
128 fprintf (stdout, "%s\n", ztld);
129 fprintf (stdout, "\n");
130 pow = GNUNET_malloc (GNUNET_MAX_POW_SIZE);
131 GNUNET_GNSRECORD_pow_init (id_priv,
132 pow);
133 ph = GNUNET_GNSRECORD_pow_start (pow,
134 TEST_EPOCHS,
135 TEST_DIFFICULTY);
136 fprintf (stdout, "Difficulty (%d base difficulty + %d epochs): %d\n\n",
137 TEST_DIFFICULTY,
138 TEST_EPOCHS,
139 TEST_DIFFICULTY + TEST_EPOCHS);
140 uint64_t pow_passes = 0;
141 while (GNUNET_YES != GNUNET_GNSRECORD_pow_round (ph))
142 {
143 pow_passes++;
144 }
145 struct GNUNET_GNSRECORD_SignaturePurposePS *purp;
146 purp = GNR_create_signature_message (pow);
147 fprintf (stdout, "Signed message:\n");
148 print_bytes (purp,
149 ntohl (purp->purpose.size),
150 8);
151 printf ("\n");
152 GNUNET_free (purp);
153
154 exp = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
155 TEST_EPOCHS);
156 GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_check_pow (pow,
157 TEST_DIFFICULTY,
158 exp));
159 fprintf (stdout, "Proof:\n");
160 print_bytes (pow,
161 GNUNET_GNSRECORD_proof_get_size (pow),
162 8);
163 GNUNET_free (ph);
164
165}
166
167
168/**
169 * Main function that will be run.
170 *
171 * @param cls closure
172 * @param args remaining command-line arguments
173 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
174 * @param cfg configuration
175 */
176static void
177run (void *cls,
178 char *const *args,
179 const char *cfgfile,
180 const struct GNUNET_CONFIGURATION_Handle *cfg)
181{
182 struct GNUNET_CRYPTO_PrivateKey id_priv;
183
184 id_priv.type = htonl (GNUNET_PUBLIC_KEY_TYPE_ECDSA);
185 parsehex (d_pkey,(char*) &id_priv.ecdsa_key, sizeof (id_priv.ecdsa_key), 1);
186
187 fprintf (stdout, "Zone private key (d, big-endian):\n");
188 print_bytes_ (&id_priv.ecdsa_key, sizeof(id_priv.ecdsa_key), 8, 1);
189 run_with_key (&id_priv);
190 printf ("\n");
191 id_priv.type = htonl (GNUNET_PUBLIC_KEY_TYPE_EDDSA);
192 parsehex (d_edkey,(char*) &id_priv.eddsa_key, sizeof (id_priv.eddsa_key), 0);
193
194 fprintf (stdout, "Zone private key (d):\n");
195 print_bytes (&id_priv.eddsa_key, sizeof(id_priv.eddsa_key), 8);
196 run_with_key (&id_priv);
197}
198
199
200/**
201 * The main function of the test vector generation tool.
202 *
203 * @param argc number of arguments from the command line
204 * @param argv command line arguments
205 * @return 0 ok, 1 on error
206 */
207int
208main (int argc,
209 char *const *argv)
210{
211 const struct GNUNET_GETOPT_CommandLineOption options[] = {
212 GNUNET_GETOPT_OPTION_END
213 };
214
215 GNUNET_assert (GNUNET_OK ==
216 GNUNET_log_setup ("gnunet-revocation-tvg",
217 "INFO",
218 NULL));
219 if (GNUNET_OK !=
220 GNUNET_PROGRAM_run (argc, argv,
221 "gnunet-revocation-tvg",
222 "Generate test vectors for revocation",
223 options,
224 &run, NULL))
225 return 1;
226 return 0;
227}
228
229
230/* end of gnunet-revocation-tvg.c */
diff --git a/src/cli/revocation/gnunet-revocation.c b/src/cli/revocation/gnunet-revocation.c
new file mode 100644
index 000000000..add9a003b
--- /dev/null
+++ b/src/cli/revocation/gnunet-revocation.c
@@ -0,0 +1,581 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 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 revocation/gnunet-revocation.c
23 * @brief tool for revoking public keys
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_gnsrecord_lib.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_revocation_service.h"
30
31/**
32 * Pow passes
33 */
34static unsigned int pow_passes = 1;
35
36/**
37 * Final status code.
38 */
39static int ret;
40
41/**
42 * Was "-p" specified?
43 */
44static int perform;
45
46/**
47 * -f option.
48 */
49static char *filename;
50
51/**
52 * -R option
53 */
54static char *revoke_ego;
55
56/**
57 * -t option.
58 */
59static char *test_ego;
60
61/**
62 * -e option.
63 */
64static unsigned int epochs = 1;
65
66/**
67 * Handle for revocation query.
68 */
69static struct GNUNET_REVOCATION_Query *q;
70
71/**
72 * Handle for revocation.
73 */
74static struct GNUNET_REVOCATION_Handle *h;
75
76/**
77 * Handle for our ego lookup.
78 */
79static struct GNUNET_IDENTITY_EgoLookup *el;
80
81/**
82 * Our configuration.
83 */
84static const struct GNUNET_CONFIGURATION_Handle *cfg;
85
86/**
87 * Number of matching bits required for revocation.
88 */
89static unsigned long long matching_bits;
90
91/**
92 * Epoch length
93 */
94static struct GNUNET_TIME_Relative epoch_duration;
95
96/**
97 * Task used for proof-of-work calculation.
98 */
99static struct GNUNET_SCHEDULER_Task *pow_task;
100
101/**
102 * Proof-of-work object
103 */
104static struct GNUNET_GNSRECORD_PowP *proof_of_work;
105
106/**
107 * Function run if the user aborts with CTRL-C.
108 *
109 * @param cls closure
110 */
111static void
112do_shutdown (void *cls)
113{
114 fprintf (stderr, "%s", _ ("Shutting down...\n"));
115 if (NULL != el)
116 {
117 GNUNET_IDENTITY_ego_lookup_cancel (el);
118 el = NULL;
119 }
120 if (NULL != q)
121 {
122 GNUNET_REVOCATION_query_cancel (q);
123 q = NULL;
124 }
125 if (NULL != h)
126 {
127 GNUNET_REVOCATION_revoke_cancel (h);
128 h = NULL;
129 }
130}
131
132
133/**
134 * Print the result from a revocation query.
135 *
136 * @param cls NULL
137 * @param is_valid #GNUNET_YES if the key is still valid, #GNUNET_NO if not, #GNUNET_SYSERR on error
138 */
139static void
140print_query_result (void *cls, int is_valid)
141{
142 q = NULL;
143 switch (is_valid)
144 {
145 case GNUNET_YES:
146 fprintf (stdout, _ ("Key `%s' is valid\n"), test_ego);
147 break;
148
149 case GNUNET_NO:
150 fprintf (stdout, _ ("Key `%s' has been revoked\n"), test_ego);
151 break;
152
153 case GNUNET_SYSERR:
154 fprintf (stdout, "%s", _ ("Internal error\n"));
155 break;
156
157 default:
158 GNUNET_break (0);
159 break;
160 }
161 GNUNET_SCHEDULER_shutdown ();
162}
163
164
165/**
166 * Print the result from a revocation request.
167 *
168 * @param cls NULL
169 * @param is_valid #GNUNET_YES if the key is still valid, #GNUNET_NO if not, #GNUNET_SYSERR on error
170 */
171static void
172print_revocation_result (void *cls, int is_valid)
173{
174 h = NULL;
175 switch (is_valid)
176 {
177 case GNUNET_YES:
178 if (NULL != revoke_ego)
179 fprintf (stdout,
180 _ ("Key for ego `%s' is still valid, revocation failed (!)\n"),
181 revoke_ego);
182 else
183 fprintf (stdout, "%s", _ ("Revocation failed (!)\n"));
184 break;
185
186 case GNUNET_NO:
187 if (NULL != revoke_ego)
188 fprintf (stdout,
189 _ ("Key for ego `%s' has been successfully revoked\n"),
190 revoke_ego);
191 else
192 fprintf (stdout, "%s", _ ("Revocation successful.\n"));
193 break;
194
195 case GNUNET_SYSERR:
196 fprintf (stdout,
197 "%s",
198 _ ("Internal error, key revocation might have failed\n"));
199 break;
200
201 default:
202 GNUNET_break (0);
203 break;
204 }
205 GNUNET_SCHEDULER_shutdown ();
206}
207
208
209/**
210 * Perform the revocation.
211 */
212static void
213perform_revocation ()
214{
215 h = GNUNET_REVOCATION_revoke (cfg,
216 proof_of_work,
217 &print_revocation_result,
218 NULL);
219}
220
221
222/**
223 * Write the current state of the revocation data
224 * to disk.
225 *
226 * @param rd data to sync
227 */
228static void
229sync_pow ()
230{
231 size_t psize = GNUNET_GNSRECORD_proof_get_size (proof_of_work);
232 if ((NULL != filename) &&
233 (GNUNET_OK !=
234 GNUNET_DISK_fn_write (filename,
235 proof_of_work,
236 psize,
237 GNUNET_DISK_PERM_USER_READ
238 | GNUNET_DISK_PERM_USER_WRITE)))
239 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", filename);
240}
241
242
243/**
244 * Perform the proof-of-work calculation.
245 *
246 * @param cls the `struct RevocationData`
247 */
248static void
249calculate_pow_shutdown (void *cls)
250{
251 struct GNUNET_GNSRECORD_PowCalculationHandle *ph = cls;
252 fprintf (stderr, "%s", _ ("Cancelling calculation.\n"));
253 sync_pow ();
254 if (NULL != pow_task)
255 {
256 GNUNET_SCHEDULER_cancel (pow_task);
257 pow_task = NULL;
258 }
259 if (NULL != ph)
260 GNUNET_GNSRECORD_pow_stop (ph);
261}
262
263
264/**
265 * Perform the proof-of-work calculation.
266 *
267 * @param cls the `struct RevocationData`
268 */
269static void
270calculate_pow (void *cls)
271{
272 struct GNUNET_GNSRECORD_PowCalculationHandle *ph = cls;
273 size_t psize;
274
275 /* store temporary results */
276 pow_task = NULL;
277 if (0 == (pow_passes % 128))
278 sync_pow ();
279 /* actually do POW calculation */
280 if (GNUNET_OK == GNUNET_GNSRECORD_pow_round (ph))
281 {
282 psize = GNUNET_GNSRECORD_proof_get_size (proof_of_work);
283 if (NULL != filename)
284 {
285 (void) GNUNET_DISK_directory_remove (filename);
286 if (GNUNET_OK !=
287 GNUNET_DISK_fn_write (filename,
288 proof_of_work,
289 psize,
290 GNUNET_DISK_PERM_USER_READ
291 | GNUNET_DISK_PERM_USER_WRITE))
292 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", filename);
293 }
294 if (perform)
295 {
296 perform_revocation ();
297 }
298 else
299 {
300 fprintf (stderr, "%s", "\n");
301 fprintf (stderr,
302 _ ("Revocation certificate for `%s' stored in `%s'\n"),
303 revoke_ego,
304 filename);
305 GNUNET_SCHEDULER_shutdown ();
306 }
307 return;
308 }
309 pow_passes++;
310 pow_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
311 &calculate_pow,
312 ph);
313
314}
315
316
317/**
318 * Function called with the result from the ego lookup.
319 *
320 * @param cls closure
321 * @param ego the ego, NULL if not found
322 */
323static void
324ego_callback (void *cls, struct GNUNET_IDENTITY_Ego *ego)
325{
326 struct GNUNET_CRYPTO_PublicKey key;
327 const struct GNUNET_CRYPTO_PrivateKey *privkey;
328 struct GNUNET_GNSRECORD_PowCalculationHandle *ph = NULL;
329 size_t psize;
330
331 el = NULL;
332 if (NULL == ego)
333 {
334 fprintf (stdout, _ ("Ego `%s' not found.\n"), revoke_ego);
335 GNUNET_SCHEDULER_shutdown ();
336 return;
337 }
338 GNUNET_IDENTITY_ego_get_public_key (ego, &key);
339 privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
340 proof_of_work = GNUNET_malloc (GNUNET_MAX_POW_SIZE);
341 if ((NULL != filename) && (GNUNET_YES == GNUNET_DISK_file_test (filename)) &&
342 (0 < (psize =
343 GNUNET_DISK_fn_read (filename, proof_of_work,
344 GNUNET_MAX_POW_SIZE))))
345 {
346 ssize_t ksize = GNUNET_CRYPTO_public_key_get_length (&key);
347 if (0 > ksize)
348 {
349 fprintf (stderr,
350 _ ("Error: Key is invalid\n"));
351 return;
352 }
353 if (((psize - sizeof (*proof_of_work)) < ksize) || // Key too small
354 (0 != memcmp (&proof_of_work[1], &key, ksize))) // Keys do not match
355 {
356 fprintf (stderr,
357 _ ("Error: revocation certificate in `%s' is not for `%s'\n"),
358 filename,
359 revoke_ego);
360 return;
361 }
362 if (GNUNET_YES ==
363 GNUNET_GNSRECORD_check_pow (proof_of_work,
364 (unsigned int) matching_bits,
365 epoch_duration))
366 {
367 fprintf (stderr, "%s", _ ("Revocation certificate ready\n"));
368 if (perform)
369 perform_revocation ();
370 else
371 GNUNET_SCHEDULER_shutdown ();
372 return;
373 }
374 /**
375 * Certificate not yet ready
376 */
377 fprintf (stderr,
378 "%s",
379 _ ("Continuing calculation where left off...\n"));
380 ph = GNUNET_GNSRECORD_pow_start (proof_of_work,
381 epochs,
382 matching_bits);
383 }
384 fprintf (stderr,
385 "%s",
386 _ ("Revocation certificate not ready, calculating proof of work\n"));
387 if (NULL == ph)
388 {
389 GNUNET_GNSRECORD_pow_init (privkey,
390 proof_of_work);
391 ph = GNUNET_GNSRECORD_pow_start (proof_of_work,
392 epochs, /* Epochs */
393 matching_bits);
394 }
395 pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
396 GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, ph);
397}
398
399
400/**
401 * Main function that will be run by the scheduler.
402 *
403 * @param cls closure
404 * @param args remaining command-line arguments
405 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
406 * @param c configuration
407 */
408static void
409run (void *cls,
410 char *const *args,
411 const char *cfgfile,
412 const struct GNUNET_CONFIGURATION_Handle *c)
413{
414 struct GNUNET_CRYPTO_PublicKey pk;
415 size_t psize;
416
417 cfg = c;
418 if (NULL != test_ego)
419 {
420 if (GNUNET_OK !=
421 GNUNET_CRYPTO_public_key_from_string (test_ego,
422 &pk))
423 {
424 fprintf (stderr, _ ("Public key `%s' malformed\n"), test_ego);
425 return;
426 }
427 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
428 q = GNUNET_REVOCATION_query (cfg, &pk, &print_query_result, NULL);
429 if (NULL != revoke_ego)
430 fprintf (
431 stderr,
432 "%s",
433 _ (
434 "Testing and revoking at the same time is not allowed, only executing test.\n"));
435 return;
436 }
437 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
438 "REVOCATION",
439 "WORKBITS",
440 &matching_bits))
441 {
442 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
443 "REVOCATION",
444 "WORKBITS");
445 return;
446 }
447 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
448 "REVOCATION",
449 "EPOCH_DURATION",
450 &epoch_duration))
451 {
452 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
453 "REVOCATION",
454 "EPOCH_DURATION");
455 return;
456 }
457
458 if (NULL != revoke_ego)
459 {
460 if (! perform && (NULL == filename))
461 {
462 fprintf (stderr,
463 "%s",
464 _ ("No filename to store revocation certificate given.\n"));
465 return;
466 }
467 /* main code here */
468 el = GNUNET_IDENTITY_ego_lookup (cfg, revoke_ego, &ego_callback, NULL);
469 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
470 return;
471 }
472 if ((NULL != filename) && (perform))
473 {
474 size_t bread;
475 proof_of_work = GNUNET_malloc (GNUNET_MAX_POW_SIZE);
476 if (0 < (bread = GNUNET_DISK_fn_read (filename,
477 proof_of_work,
478 GNUNET_MAX_POW_SIZE)))
479 {
480 fprintf (stderr,
481 _ ("Failed to read revocation certificate from `%s'\n"),
482 filename);
483 return;
484 }
485 psize = GNUNET_GNSRECORD_proof_get_size (proof_of_work);
486 if (bread != psize)
487 {
488 fprintf (stderr,
489 _ ("Revocation certificate corrupted in `%s'\n"),
490 filename);
491 return;
492 }
493 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
494 if (GNUNET_YES !=
495 GNUNET_GNSRECORD_check_pow (proof_of_work,
496 (unsigned int) matching_bits,
497 epoch_duration))
498 {
499 struct GNUNET_GNSRECORD_PowCalculationHandle *ph;
500 ph = GNUNET_GNSRECORD_pow_start (proof_of_work,
501 epochs, /* Epochs */
502 matching_bits);
503
504 pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
505 GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, ph);
506 return;
507 }
508 perform_revocation ();
509 return;
510 }
511 fprintf (stderr, "%s", _ ("No action specified. Nothing to do.\n"));
512}
513
514
515/**
516 * The main function of gnunet-revocation.
517 *
518 * @param argc number of arguments from the command line
519 * @param argv command line arguments
520 * @return 0 ok, 1 on error
521 */
522int
523main (int argc, char *const *argv)
524{
525 struct GNUNET_GETOPT_CommandLineOption options[] = {
526 GNUNET_GETOPT_option_string ('f',
527 "filename",
528 "NAME",
529 gettext_noop (
530 "use NAME for the name of the revocation file"),
531 &filename),
532
533 GNUNET_GETOPT_option_string (
534 'R',
535 "revoke",
536 "NAME",
537 gettext_noop (
538 "revoke the private key associated for the the private key associated with the ego NAME "),
539 &revoke_ego),
540
541 GNUNET_GETOPT_option_flag (
542 'p',
543 "perform",
544 gettext_noop (
545 "actually perform revocation, otherwise we just do the precomputation"),
546 &perform),
547
548 GNUNET_GETOPT_option_string ('t',
549 "test",
550 "KEY",
551 gettext_noop (
552 "test if the public key KEY has been revoked"),
553 &test_ego),
554 GNUNET_GETOPT_option_uint ('e',
555 "epochs",
556 "EPOCHS",
557 gettext_noop (
558 "number of epochs to calculate for"),
559 &epochs),
560
561 GNUNET_GETOPT_OPTION_END
562 };
563
564 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
565 return 2;
566
567 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
568 argv,
569 "gnunet-revocation",
570 gettext_noop ("help text"),
571 options,
572 &run,
573 NULL))
574 ? ret
575 : 1;
576 GNUNET_free_nz ((void *) argv);
577 return ret;
578}
579
580
581/* end of gnunet-revocation.c */
diff --git a/src/cli/revocation/meson.build b/src/cli/revocation/meson.build
new file mode 100644
index 000000000..090b381df
--- /dev/null
+++ b/src/cli/revocation/meson.build
@@ -0,0 +1,22 @@
1executable ('gnunet-revocation',
2 ['gnunet-revocation.c'],
3 dependencies: [libgnunetrevocation_dep,
4 libgnunetutil_dep,
5 libgnunetstatistics_dep,
6 libgnunetcore_dep,
7 libgnunetgnsrecord_dep,
8 libgnunetsetu_dep,
9 libgnunetidentity_dep],
10 include_directories: [incdir, configuration_inc],
11 install: true,
12 install_dir: get_option('bindir'))
13
14executable ('gnunet-revocation-tvg',
15 ['gnunet-revocation.c'],
16 dependencies: [libgnunetrevocation_dep,
17 libgnunetutil_dep,
18 libgnunetgnsrecord_dep,
19 libgnunetidentity_dep],
20 include_directories: [incdir, configuration_inc],
21 install: false)
22
diff --git a/src/cli/revocation/test_local_revocation.py.in b/src/cli/revocation/test_local_revocation.py.in
new file mode 100644
index 000000000..e667c10ce
--- /dev/null
+++ b/src/cli/revocation/test_local_revocation.py.in
@@ -0,0 +1,129 @@
1#!@PYTHONEXE@
2# This file is part of GNUnet.
3# (C) 2010, 2018 Christian Grothoff (and other contributing authors)
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# Testcase for ego revocation
21
22import sys
23import os
24import subprocess
25import re
26import shutil
27
28if os.name == 'posix':
29 config = 'gnunet-config'
30 gnunetarm = 'gnunet-arm'
31 ident = 'gnunet-identity'
32 revoc = './gnunet-revocation'
33elif os.name == 'nt':
34 config = 'gnunet-config.exe'
35 gnunetarm = 'gnunet-arm.exe'
36 ident = 'gnunet-identity.exe'
37 revoc = './gnunet-revocation.exe'
38
39TEST_CONFIGURATION = "test_revocation.conf"
40TEST_REVOCATION_EGO = "revoc_test"
41
42get_clean = subprocess.Popen([
43 config, '-c', TEST_CONFIGURATION, '-s', 'PATHS', '-o', 'GNUNET_HOME', '-f'
44],
45 stdout=subprocess.PIPE)
46cleandir, x = get_clean.communicate()
47cleandir = cleandir.decode("utf-8")
48cleandir = cleandir.rstrip('\n').rstrip('\r')
49
50if os.path.isdir(cleandir):
51 shutil.rmtree(cleandir, True)
52
53res = 0
54arm = subprocess.Popen([gnunetarm, '-s', '-c', TEST_CONFIGURATION])
55arm.communicate()
56
57try:
58 print("Creating an ego " + TEST_REVOCATION_EGO)
59 sys.stdout.flush()
60 sys.stderr.flush()
61 idc = subprocess.Popen([
62 ident, '-C', TEST_REVOCATION_EGO, '-c', TEST_CONFIGURATION
63 ])
64 idc.communicate()
65 if idc.returncode != 0:
66 raise Exception(
67 "gnunet-identity failed to create an ego `" + TEST_REVOCATION_EGO +
68 "'"
69 )
70
71 sys.stdout.flush()
72 sys.stderr.flush()
73 idd = subprocess.Popen([ident, '-d'], stdout=subprocess.PIPE)
74 rev_key, x = idd.communicate()
75 rev_key = rev_key.decode("utf-8")
76 if len(rev_key.split()) < 3:
77 raise Exception("can't get revocation key out of `" + rev_key + "'")
78 rev_key = rev_key.split()[2]
79
80 print("Testing key " + rev_key)
81 sys.stdout.flush()
82 sys.stderr.flush()
83 tst = subprocess.Popen([revoc, '-t', rev_key, '-c', TEST_CONFIGURATION],
84 stdout=subprocess.PIPE)
85 output_not_revoked, x = tst.communicate()
86 output_not_revoked = output_not_revoked.decode("utf-8")
87 if tst.returncode != 0:
88 raise Exception(
89 "gnunet-revocation failed to test a key - " + str(tst.returncode) +
90 ": " + output_not_revoked
91 )
92 if 'valid' not in output_not_revoked:
93 res = 1
94 print("Key was not valid")
95 else:
96 print("Key was valid")
97
98 print("Revoking key " + rev_key)
99 sys.stdout.flush()
100 sys.stderr.flush()
101 rev = subprocess.Popen([
102 revoc, '-R', TEST_REVOCATION_EGO, '-p', '-c', TEST_CONFIGURATION
103 ])
104 rev.communicate()
105 if rev.returncode != 0:
106 raise Exception("gnunet-revocation failed to revoke a key")
107
108 print("Testing revoked key " + rev_key)
109 sys.stdout.flush()
110 sys.stderr.flush()
111 tst = subprocess.Popen([revoc, '-t', rev_key, '-c', TEST_CONFIGURATION],
112 stdout=subprocess.PIPE)
113 output_revoked, x = tst.communicate()
114 output_revoked = output_revoked.decode("utf-8")
115 if tst.returncode != 0:
116 raise Exception("gnunet-revocation failed to test a revoked key")
117 if 'revoked' not in output_revoked:
118 res = 1
119 print("Key was not revoked")
120 else:
121 print("Key was revoked")
122
123finally:
124 arm = subprocess.Popen([gnunetarm, '-e', '-c', TEST_CONFIGURATION])
125 arm.communicate()
126 if os.path.isdir(cleandir):
127 shutil.rmtree(cleandir, True)
128
129sys.exit(res)
diff --git a/src/cli/statistics/.gitignore b/src/cli/statistics/.gitignore
new file mode 100644
index 000000000..2a7218e76
--- /dev/null
+++ b/src/cli/statistics/.gitignore
@@ -0,0 +1 @@
gnunet-statistics
diff --git a/src/cli/statistics/Makefile.am b/src/cli/statistics/Makefile.am
new file mode 100644
index 000000000..29160ed71
--- /dev/null
+++ b/src/cli/statistics/Makefile.am
@@ -0,0 +1,40 @@
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
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13bin_PROGRAMS = \
14 gnunet-statistics
15
16gnunet_statistics_SOURCES = \
17 gnunet-statistics.c
18gnunet_statistics_LDADD = \
19 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
20 $(top_builddir)/src/lib/util/libgnunetutil.la \
21 $(GN_LIBINTL)
22
23# Config file still in service folder
24#if HAVE_PYTHON
25#check_SCRIPTS = \
26# test_gnunet_statistics.py
27#endif
28#
29#SUFFIXES = .py.in .py
30#.py.in.py:
31# $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/$< > $@
32# chmod +x $@
33#
34#test_gnunet_statistics.py: test_gnunet_statistics.py.in Makefile
35# $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/test_gnunet_statistics.py.in > test_gnunet_statistics.py
36# chmod +x test_gnunet_statistics.py
37#
38#EXTRA_DIST = \
39# test_statistics_api_data.conf \
40# test_gnunet_statistics.py.in
diff --git a/src/cli/statistics/gnunet-statistics.c b/src/cli/statistics/gnunet-statistics.c
new file mode 100644
index 000000000..3336980d1
--- /dev/null
+++ b/src/cli/statistics/gnunet-statistics.c
@@ -0,0 +1,889 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004-2007, 2009, 2016 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 statistics/gnunet-statistics.c
23 * @brief tool to obtain statistics
24 * @author Christian Grothoff
25 * @author Igor Wronsky
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_statistics_service.h"
30#include "../../service/statistics/statistics.h"
31
32
33/**
34 * Final status code.
35 */
36static int ret;
37
38/**
39 * Set to subsystem that we're going to get stats for (or NULL for all).
40 */
41static char *subsystem;
42
43/**
44 * The path of the testbed data.
45 */
46static char *path_testbed;
47
48/**
49 * Set to the specific stat value that we are after (or NULL for all).
50 */
51static char *name;
52
53/**
54 * Make the value that is being set persistent.
55 */
56static int persistent;
57
58/**
59 * Watch value continuously
60 */
61static int watch;
62
63/**
64 * Quiet mode
65 */
66static int quiet;
67
68/**
69 * @brief Separator string for csv.
70 */
71static char *csv_separator;
72
73/**
74 * Remote host
75 */
76static char *remote_host;
77
78/**
79 * Remote host's port
80 */
81static unsigned long long remote_port;
82
83/**
84 * Value to set
85 */
86static unsigned long long set_val;
87
88/**
89 * Set operation
90 */
91static int set_value;
92
93/**
94 * @brief Representation of all (testbed) nodes.
95 */
96static struct Node
97{
98 /**
99 * @brief Index of the node in this array.
100 */
101 unsigned index_node;
102
103 /**
104 * @brief Configuration handle for this node
105 */
106 struct GNUNET_CONFIGURATION_Handle *conf;
107
108 /**
109 * Handle for pending GET operation.
110 */
111 struct GNUNET_STATISTICS_GetHandle *gh;
112
113 /**
114 * @brief Statistics handle nodes.
115 */
116 struct GNUNET_STATISTICS_Handle *handle;
117 /**
118 * @brief Identifier for shutdown task for this node.
119 */
120 struct GNUNET_SCHEDULER_Task *shutdown_task;
121} *nodes;
122
123/**
124 * @brief Number of configurations of all (testbed) nodes.
125 */
126static unsigned num_nodes;
127
128/**
129 * @brief Set of values for a combination of subsystem and name.
130 */
131struct ValueSet
132{
133 /**
134 * @brief Subsystem of the valueset.
135 */
136 char *subsystem;
137
138 /**
139 * @brief Name of the valueset.
140 */
141 char *name;
142
143 /**
144 * @brief The values.
145 */
146 uint64_t *values;
147
148 /**
149 * @brief Persistence of the values.
150 */
151 int is_persistent;
152};
153
154
155/**
156 * @brief Collection of all values (represented with #ValueSet).
157 */
158static struct GNUNET_CONTAINER_MultiHashMap *values;
159
160/**
161 * @brief Number of nodes that have their values ready.
162 */
163static int num_nodes_ready;
164
165/**
166 * @brief Number of nodes that have their values ready.
167 */
168static int num_nodes_ready_shutdown;
169
170
171/**
172 * @brief Create a new #ValueSet
173 *
174 * @param subsystem Subsystem of the valueset.
175 * @param name Name of the valueset.
176 * @param num_values Number of values in valueset - number of peers.
177 * @param is_persistent Persistence status of values.
178 * @return Newly allocated #ValueSet.
179 */
180static struct ValueSet *
181new_value_set (const char *subsystem,
182 const char *name,
183 unsigned num_values,
184 int is_persistent)
185{
186 struct ValueSet *value_set;
187
188 value_set = GNUNET_new (struct ValueSet);
189 value_set->subsystem = GNUNET_strdup (subsystem);
190 value_set->name = GNUNET_strdup (name);
191 value_set->values = GNUNET_new_array (num_values,
192 uint64_t);
193 value_set->is_persistent = persistent;
194 return value_set;
195}
196
197
198/**
199 * @brief Print the (collected) values.
200 *
201 * Implements #GNUNET_CONTAINER_HashMapIterator.
202 *
203 * @param cls Closure - unused
204 * @param key #GNUNET_HashCode key of #GNUNET_CONTAINER_MultiHashMap iterator -
205 * unused
206 * @param value Values represented as #ValueSet.
207 * @return #GNUNET_YES - continue iteration.
208 */
209static int
210printer (void *cls,
211 const struct GNUNET_HashCode *key,
212 void *value)
213{
214 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
215 const char *now_str;
216 struct ValueSet *value_set = value;
217
218 if (quiet == GNUNET_NO)
219 {
220 if (GNUNET_YES == watch)
221 {
222 now_str = GNUNET_STRINGS_absolute_time_to_string (now);
223 fprintf (stdout,
224 "%24s%s %s%s%12s%s %s%50s%s%s ",
225 now_str,
226 csv_separator,
227 value_set->is_persistent ? "!" : " ",
228 csv_separator,
229 value_set->subsystem,
230 csv_separator,
231 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
232 _ (value_set->name),
233 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
234 (0 == strlen (csv_separator) ? ":" : csv_separator));
235 }
236 else
237 {
238 fprintf (stdout,
239 "%s%s%12s%s %s%50s%s%s ",
240 value_set->is_persistent ? "!" : " ",
241 csv_separator,
242 value_set->subsystem,
243 csv_separator,
244 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
245 _ (value_set->name),
246 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
247 (0 == strlen (csv_separator) ? ":" : csv_separator));
248 }
249 }
250 for (unsigned i = 0; i < num_nodes; i++)
251 {
252 fprintf (stdout,
253 "%16llu%s",
254 (unsigned long long) value_set->values[i],
255 csv_separator);
256 }
257 fprintf (stdout, "\n");
258 GNUNET_free (value_set->subsystem);
259 GNUNET_free (value_set->name);
260 GNUNET_free (value_set->values);
261 GNUNET_free (value_set);
262 return GNUNET_YES;
263}
264
265
266/**
267 * Callback function to process statistic values.
268 *
269 * @param cls closure
270 * @param subsystem name of subsystem that created the statistic
271 * @param name the name of the datum
272 * @param value the current value
273 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
274 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
275 */
276static int
277printer_watch (void *cls,
278 const char *subsystem,
279 const char *name,
280 uint64_t value,
281 int is_persistent)
282{
283 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
284 const char *now_str;
285
286 if (quiet == GNUNET_NO)
287 {
288 if (GNUNET_YES == watch)
289 {
290 now_str = GNUNET_STRINGS_absolute_time_to_string (now);
291 fprintf (stdout,
292 "%24s%s %s%s%12s%s %s%50s%s%s %16llu\n",
293 now_str,
294 csv_separator,
295 is_persistent ? "!" : " ",
296 csv_separator,
297 subsystem,
298 csv_separator,
299 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
300 _ (name),
301 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
302 (0 == strlen (csv_separator) ? ":" : csv_separator),
303 (unsigned long long) value);
304 }
305 else
306 {
307 fprintf (stdout,
308 "%s%s%12s%s %s%50s%s%s %16llu\n",
309 is_persistent ? "!" : " ",
310 csv_separator,
311 subsystem,
312 csv_separator,
313 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
314 _ (name),
315 (0 == strlen (csv_separator) ? "" : "\""), /* quotes if csv */
316 (0 == strlen (csv_separator) ? ":" : csv_separator),
317 (unsigned long long) value);
318 }
319 }
320 else
321 fprintf (stdout, "%llu\n", (unsigned long long) value);
322
323 return GNUNET_OK;
324}
325
326
327/**
328 * @brief Clean all data structures related to given node.
329 *
330 * Also clears global structures if we are the last node to clean.
331 *
332 * @param cls the index of the node
333 */
334static void
335clean_node (void *cls)
336{
337 const unsigned index_node = *(unsigned *) cls;
338 struct GNUNET_STATISTICS_Handle *h;
339 struct GNUNET_STATISTICS_GetHandle *gh;
340
341 if ((NULL != path_testbed) && /* were issued with -t <testbed-path> option */
342 (NULL != nodes[index_node].conf))
343 {
344 GNUNET_CONFIGURATION_destroy (nodes[index_node].conf);
345 nodes[index_node].conf = NULL;
346 }
347
348 h = nodes[index_node].handle;
349 gh = nodes[index_node].gh;
350
351 if (NULL != gh)
352 {
353 GNUNET_STATISTICS_get_cancel (gh);
354 gh = NULL;
355 }
356 if (GNUNET_YES == watch)
357 {
358 GNUNET_assert (
359 GNUNET_OK ==
360 GNUNET_STATISTICS_watch_cancel (h,
361 subsystem,
362 name,
363 &printer_watch,
364 &nodes[index_node].index_node));
365 }
366
367 if (NULL != h)
368 {
369 GNUNET_STATISTICS_destroy (h, GNUNET_NO);
370 h = NULL;
371 }
372
373 num_nodes_ready_shutdown++;
374}
375
376
377/**
378 * @brief Print and shutdown
379 *
380 * @param cls unused
381 */
382static void
383print_finish (void *cls)
384{
385 GNUNET_CONTAINER_multihashmap_iterate (values,
386 &printer,
387 NULL);
388 GNUNET_CONTAINER_multihashmap_destroy (values);
389 GNUNET_SCHEDULER_shutdown ();
390}
391
392
393/**
394 * @brief Called once all statistic values are available.
395 *
396 * Implements #GNUNET_STATISTICS_Callback
397 *
398 * @param cls Closure - The index of the node.
399 * @param success Whether statistics were obtained successfully.
400 */
401static void
402continuation_print (void *cls,
403 int success)
404{
405 const unsigned index_node = *(unsigned *) cls;
406
407 nodes[index_node].gh = NULL;
408 if (GNUNET_OK != success)
409 {
410 if (NULL == remote_host)
411 fprintf (stderr,
412 "%s",
413 _ ("Failed to obtain statistics.\n"));
414 else
415 fprintf (stderr,
416 _ ("Failed to obtain statistics from host `%s:%llu'\n"),
417 remote_host,
418 remote_port);
419 ret = 1;
420 }
421 if (NULL != nodes[index_node].shutdown_task)
422 {
423 GNUNET_SCHEDULER_cancel (nodes[index_node].shutdown_task);
424 nodes[index_node].shutdown_task = NULL;
425 }
426 GNUNET_SCHEDULER_add_now (&clean_node,
427 &nodes[index_node].index_node);
428 num_nodes_ready++;
429 if (num_nodes_ready == num_nodes)
430 {
431 GNUNET_SCHEDULER_add_now (&print_finish,
432 NULL);
433 }
434}
435
436
437/**
438 * Function called last by the statistics code.
439 *
440 * @param cls closure
441 * @param success #GNUNET_OK if statistics were
442 * successfully obtained, #GNUNET_SYSERR if not.
443 */
444static void
445cleanup (void *cls,
446 int success)
447{
448 for (unsigned i = 0; i < num_nodes; i++)
449 {
450 nodes[i].gh = NULL;
451 }
452 if (GNUNET_OK != success)
453 {
454 if (NULL == remote_host)
455 fprintf (stderr, "%s", _ ("Failed to obtain statistics.\n"));
456 else
457 fprintf (stderr,
458 _ ("Failed to obtain statistics from host `%s:%llu'\n"),
459 remote_host,
460 remote_port);
461 ret = 1;
462 }
463 GNUNET_SCHEDULER_shutdown ();
464}
465
466
467/**
468 * @brief Iterate over statistics values and store them in #values.
469 * They will be printed once all are available.
470 *
471 * @param cls Cosure - Node index.
472 * @param subsystem Subsystem of the value.
473 * @param name Name of the value.
474 * @param value Value itself.
475 * @param is_persistent Persistence.
476 * @return #GNUNET_OK - continue.
477 */
478static int
479collector (void *cls,
480 const char *subsystem,
481 const char *name,
482 uint64_t value,
483 int is_persistent)
484{
485 const unsigned index_node = *(unsigned *) cls;
486 struct GNUNET_HashCode *key;
487 struct GNUNET_HashCode hc;
488 char *subsys_name;
489 unsigned len_subsys_name;
490 struct ValueSet *value_set;
491
492 len_subsys_name = strlen (subsystem) + 3 + strlen (name) + 1;
493 subsys_name = GNUNET_malloc (len_subsys_name);
494 sprintf (subsys_name, "%s---%s", subsystem, name);
495 key = &hc;
496 GNUNET_CRYPTO_hash (subsys_name, len_subsys_name, key);
497 GNUNET_free (subsys_name);
498 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (values, key))
499 {
500 value_set = GNUNET_CONTAINER_multihashmap_get (values, key);
501 }
502 else
503 {
504 value_set = new_value_set (subsystem, name, num_nodes, is_persistent);
505 }
506 value_set->values[index_node] = value;
507 GNUNET_assert (GNUNET_YES ==
508 GNUNET_CONTAINER_multihashmap_put (
509 values,
510 key,
511 value_set,
512 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
513 return GNUNET_OK;
514}
515
516
517/**
518 * Main task that does the actual work.
519 *
520 * @param cls closure with our configuration
521 */
522static void
523main_task (void *cls)
524{
525 unsigned index_node = *(unsigned *) cls;
526 const struct GNUNET_CONFIGURATION_Handle *cfg = nodes[index_node].conf;
527
528 if (set_value)
529 {
530 if (NULL == subsystem)
531 {
532 fprintf (stderr, "%s", _ ("Missing argument: subsystem \n"));
533 ret = 1;
534 return;
535 }
536 if (NULL == name)
537 {
538 fprintf (stderr, "%s", _ ("Missing argument: name\n"));
539 ret = 1;
540 return;
541 }
542 nodes[index_node].handle = GNUNET_STATISTICS_create (subsystem, cfg);
543 if (NULL == nodes[index_node].handle)
544 {
545 ret = 1;
546 return;
547 }
548 GNUNET_STATISTICS_set (nodes[index_node].handle,
549 name,
550 (uint64_t) set_val,
551 persistent);
552 GNUNET_STATISTICS_destroy (nodes[index_node].handle, GNUNET_YES);
553 nodes[index_node].handle = NULL;
554 return;
555 }
556 if (NULL == (nodes[index_node].handle =
557 GNUNET_STATISTICS_create ("gnunet-statistics", cfg)))
558 {
559 ret = 1;
560 return;
561 }
562 if (GNUNET_NO == watch)
563 {
564 if (NULL == (nodes[index_node].gh =
565 GNUNET_STATISTICS_get (nodes[index_node].handle,
566 subsystem,
567 name,
568 &continuation_print,
569 &collector,
570 &nodes[index_node].index_node)))
571 cleanup (nodes[index_node].handle, GNUNET_SYSERR);
572 }
573 else
574 {
575 if ((NULL == subsystem) || (NULL == name))
576 {
577 printf (_ ("No subsystem or name given\n"));
578 GNUNET_STATISTICS_destroy (nodes[index_node].handle, GNUNET_NO);
579 nodes[index_node].handle = NULL;
580 ret = 1;
581 return;
582 }
583 if (GNUNET_OK != GNUNET_STATISTICS_watch (nodes[index_node].handle,
584 subsystem,
585 name,
586 &printer_watch,
587 &nodes[index_node].index_node))
588 {
589 fprintf (stderr, _ ("Failed to initialize watch routine\n"));
590 nodes[index_node].shutdown_task =
591 GNUNET_SCHEDULER_add_now (&clean_node, &nodes[index_node].index_node);
592 return;
593 }
594 }
595 nodes[index_node].shutdown_task =
596 GNUNET_SCHEDULER_add_shutdown (&clean_node, &nodes[index_node].index_node);
597}
598
599
600/**
601 * @brief Iter over content of a node's directory to check for existence of a
602 * config file.
603 *
604 * Implements #GNUNET_FileNameCallback
605 *
606 * @param cls pointer to indicate success
607 * @param filename filename inside the directory of the potential node
608 *
609 * @return to continue iteration or not to
610 */
611static int
612iter_check_config (void *cls,
613 const char *filename)
614{
615 if (0 == strncmp (GNUNET_STRINGS_get_short_name (filename), "config", 6))
616 {
617 /* Found the config - stop iteration successfully */
618 GNUNET_array_grow (nodes, num_nodes, num_nodes + 1);
619 nodes[num_nodes - 1].conf = GNUNET_CONFIGURATION_create ();
620 nodes[num_nodes - 1].index_node = num_nodes - 1;
621 if (GNUNET_OK !=
622 GNUNET_CONFIGURATION_load (nodes[num_nodes - 1].conf, filename))
623 {
624 fprintf (stderr, "Failed loading config `%s'\n", filename);
625 return GNUNET_SYSERR;
626 }
627 return GNUNET_NO;
628 }
629 else
630 {
631 /* Continue iteration */
632 return GNUNET_OK;
633 }
634}
635
636
637/**
638 * @brief Iterates over filenames in testbed directory.
639 *
640 * Implements #GNUNET_FileNameCallback
641 *
642 * Checks if the file is a directory for a testbed node
643 * and counts the nodes.
644 *
645 * @param cls counter of nodes
646 * @param filename full path of the file in testbed
647 * @return status whether to continue iteration
648 */
649static int
650iter_testbed_path (void *cls,
651 const char *filename)
652{
653 unsigned index_node;
654
655 GNUNET_assert (NULL != filename);
656 if (1 == sscanf (GNUNET_STRINGS_get_short_name (filename),
657 "%u",
658 &index_node))
659 {
660 if (-1 == GNUNET_DISK_directory_scan (filename,
661 iter_check_config,
662 NULL))
663 {
664 /* This is probably no directory for a testbed node
665 * Go on with iteration */
666 return GNUNET_OK;
667 }
668 return GNUNET_OK;
669 }
670 return GNUNET_OK;
671}
672
673
674/**
675 * @brief Count the number of nodes running in the testbed
676 *
677 * @param path_testbed path to the testbed data
678 *
679 * @return number of running nodes
680 */
681static int
682discover_testbed_nodes (const char *path_testbed)
683{
684 int num_dir_entries;
685
686 num_dir_entries =
687 GNUNET_DISK_directory_scan (path_testbed,
688 &iter_testbed_path,
689 NULL);
690 if (-1 == num_dir_entries)
691 {
692 fprintf (stderr,
693 "Failure during scanning directory `%s'\n",
694 path_testbed);
695 return -1;
696 }
697 return 0;
698}
699
700
701/**
702 * Main function that will be run by the scheduler.
703 *
704 * @param cls closure
705 * @param args remaining command-line arguments
706 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
707 * @param cfg configuration
708 */
709static void
710run (void *cls,
711 char *const *args,
712 const char *cfgfile,
713 const struct GNUNET_CONFIGURATION_Handle *cfg)
714{
715 struct GNUNET_CONFIGURATION_Handle *c;
716
717 c = (struct GNUNET_CONFIGURATION_Handle *) cfg;
718 set_value = GNUNET_NO;
719 if (NULL == csv_separator)
720 csv_separator = "";
721 if (NULL != args[0])
722 {
723 if (1 != sscanf (args[0], "%llu", &set_val))
724 {
725 fprintf (stderr, _ ("Invalid argument `%s'\n"), args[0]);
726 ret = 1;
727 return;
728 }
729 set_value = GNUNET_YES;
730 }
731 if (NULL != remote_host)
732 {
733 if (0 == remote_port)
734 {
735 if (GNUNET_SYSERR ==
736 GNUNET_CONFIGURATION_get_value_number (cfg,
737 "statistics",
738 "PORT",
739 &remote_port))
740 {
741 fprintf (stderr,
742 _ ("A port is required to connect to host `%s'\n"),
743 remote_host);
744 return;
745 }
746 }
747 else if (65535 <= remote_port)
748 {
749 fprintf (stderr,
750 _ (
751 "A port has to be between 1 and 65535 to connect to host `%s'\n"),
752 remote_host);
753 return;
754 }
755
756 /* Manipulate configuration */
757 GNUNET_CONFIGURATION_set_value_string (c,
758 "statistics",
759 "UNIXPATH",
760 "");
761 GNUNET_CONFIGURATION_set_value_string (c,
762 "statistics",
763 "HOSTNAME",
764 remote_host);
765 GNUNET_CONFIGURATION_set_value_number (c,
766 "statistics",
767 "PORT",
768 remote_port);
769 }
770 if (NULL == path_testbed)
771 {
772 values = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
773 GNUNET_array_grow (nodes, num_nodes, 1);
774 nodes[0].index_node = 0;
775 nodes[0].conf = c;
776 GNUNET_SCHEDULER_add_now (&main_task, &nodes[0].index_node);
777 }
778 else
779 {
780 if (GNUNET_YES == watch)
781 {
782 printf (
783 _ ("Not able to watch testbed nodes (yet - feel free to implement)\n"));
784 ret = 1;
785 return;
786 }
787 values = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
788 if (-1 == discover_testbed_nodes (path_testbed))
789 {
790 return;
791 }
792 /* For each config/node collect statistics */
793 for (unsigned i = 0; i < num_nodes; i++)
794 {
795 GNUNET_SCHEDULER_add_now (&main_task, &nodes[i].index_node);
796 }
797 }
798}
799
800
801/**
802 * The main function to obtain statistics in GNUnet.
803 *
804 * @param argc number of arguments from the command line
805 * @param argv command line arguments
806 * @return 0 ok, 1 on error
807 */
808int
809main (int argc, char *const *argv)
810{
811 struct GNUNET_GETOPT_CommandLineOption options[] = {
812 GNUNET_GETOPT_option_string ('n',
813 "name",
814 "NAME",
815 gettext_noop (
816 "limit output to statistics for the given NAME"),
817 &name),
818 GNUNET_GETOPT_option_flag ('p',
819 "persistent",
820 gettext_noop (
821 "make the value being set persistent"),
822 &persistent),
823 GNUNET_GETOPT_option_string ('s',
824 "subsystem",
825 "SUBSYSTEM",
826 gettext_noop (
827 "limit output to the given SUBSYSTEM"),
828 &subsystem),
829 GNUNET_GETOPT_option_string ('S',
830 "csv-separator",
831 "CSV_SEPARATOR",
832 gettext_noop ("use as csv separator"),
833 &csv_separator),
834 GNUNET_GETOPT_option_filename ('t',
835 "testbed",
836 "TESTBED",
837 gettext_noop (
838 "path to the folder containing the testbed data"),
839 &path_testbed),
840 GNUNET_GETOPT_option_flag ('q',
841 "quiet",
842 gettext_noop (
843 "just print the statistics value"),
844 &quiet),
845 GNUNET_GETOPT_option_flag ('w',
846 "watch",
847 gettext_noop ("watch value continuously"),
848 &watch),
849 GNUNET_GETOPT_option_string ('r',
850 "remote",
851 "REMOTE",
852 gettext_noop ("connect to remote host"),
853 &remote_host),
854 GNUNET_GETOPT_option_ulong ('o',
855 "port",
856 "PORT",
857 gettext_noop ("port for remote host"),
858 &remote_port),
859 GNUNET_GETOPT_OPTION_END
860 };
861
862 remote_port = 0;
863 remote_host = NULL;
864 if (GNUNET_OK !=
865 GNUNET_STRINGS_get_utf8_args (argc, argv,
866 &argc, &argv))
867 return 2;
868
869 ret = (GNUNET_OK ==
870 GNUNET_PROGRAM_run (argc,
871 argv,
872 "gnunet-statistics [options [value]]",
873 gettext_noop (
874 "Print statistics about GNUnet operations."),
875 options,
876 &run,
877 NULL))
878 ? ret
879 : 1;
880 GNUNET_array_grow (nodes,
881 num_nodes,
882 0);
883 GNUNET_free (remote_host);
884 GNUNET_free_nz ((void *) argv);
885 return ret;
886}
887
888
889/* end of gnunet-statistics.c */
diff --git a/src/cli/statistics/meson.build b/src/cli/statistics/meson.build
new file mode 100644
index 000000000..ea0af10c7
--- /dev/null
+++ b/src/cli/statistics/meson.build
@@ -0,0 +1,8 @@
1executable ('gnunet-statistics',
2 ['gnunet-statistics.c'],
3 dependencies: [libgnunetstatistics_dep, libgnunetutil_dep],
4 include_directories: [incdir, configuration_inc],
5 install: true,
6 install_dir: get_option('bindir'))
7
8
diff --git a/src/cli/util/.gitignore b/src/cli/util/.gitignore
new file mode 100644
index 000000000..9e045f16f
--- /dev/null
+++ b/src/cli/util/.gitignore
@@ -0,0 +1,10 @@
1gnunet-config
2gnunet-config-diff
3gnunet-crypto-tvg
4gnunet-ecc
5gnunet-qr
6gnunet-resolver
7gnunet-scrypt
8gnunet-uri
9gnunet-base32
10gnunet-timeout
diff --git a/src/cli/util/Makefile.am b/src/cli/util/Makefile.am
new file mode 100644
index 000000000..cac477e13
--- /dev/null
+++ b/src/cli/util/Makefile.am
@@ -0,0 +1,108 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6libexecdir= $(pkglibdir)/libexec/
7
8pkgcfgdir= $(pkgdatadir)/config.d/
9
10if USE_COVERAGE
11 AM_CFLAGS = --coverage -O0
12 XLIB = -lgcov
13endif
14
15gnunet_config_diff_SOURCES = \
16 gnunet-config-diff.c
17gnunet_config_diff_LDADD = \
18 $(top_builddir)/src/lib/util/libgnunetutil.la
19
20GNUNET_ECC = gnunet-ecc
21GNUNET_SCRYPT = gnunet-scrypt
22
23libexec_PROGRAMS = \
24 gnunet-timeout
25
26bin_PROGRAMS = \
27 gnunet-base32 \
28 gnunet-config \
29 gnunet-resolver \
30 $(GNUNET_ECC) \
31 $(GNUNET_SCRYPT) \
32 gnunet-uri
33if HAVE_ZBAR
34bin_PROGRAMS += gnunet-qr
35endif
36
37noinst_PROGRAMS = \
38 gnunet-config-diff \
39 gnunet-crypto-tvg
40
41if ENABLE_TEST_RUN
42AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
43TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
44endif
45
46gnunet_timeout_SOURCES = \
47 gnunet-timeout.c
48
49gnunet_resolver_SOURCES = \
50 gnunet-resolver.c
51gnunet_resolver_LDADD = \
52 $(top_builddir)/src/lib/util/libgnunetutil.la \
53 $(GN_LIBINTL)
54
55gnunet_crypto_tvg_SOURCES = \
56 gnunet-crypto-tvg.c
57gnunet_crypto_tvg_LDADD = \
58 $(top_builddir)/src/lib/util/libgnunetutil.la \
59 $(GN_LIBINTL) -lgcrypt -ljansson
60
61gnunet_ecc_SOURCES = \
62 gnunet-ecc.c
63gnunet_ecc_LDADD = \
64 $(top_builddir)/src/lib/util/libgnunetutil.la \
65 $(GN_LIBINTL) -lgcrypt
66
67gnunet_base32_SOURCES = \
68 gnunet-base32.c
69gnunet_base32_LDADD = \
70 $(top_builddir)/src/lib/util/libgnunetutil.la \
71 $(GN_LIBINTL)
72
73gnunet_scrypt_SOURCES = \
74 gnunet-scrypt.c
75gnunet_scrypt_LDADD = \
76 $(top_builddir)/src/lib/util/libgnunetutil.la \
77 $(GN_LIBINTL) -lgcrypt
78
79
80gnunet_config_SOURCES = \
81 gnunet-config.c
82gnunet_config_LDADD = \
83 $(top_builddir)/src/lib/util/libgnunetutil.la \
84 $(GN_LIBINTL)
85
86gnunet_uri_SOURCES = \
87 gnunet-uri.c
88gnunet_uri_LDADD = \
89 $(top_builddir)/src/lib/util/libgnunetutil.la \
90 $(GN_LIBINTL)
91
92
93gnunet_qr_SOURCES = \
94 gnunet-qr.c
95gnunet_qr_LDADD = \
96 $(top_builddir)/src/lib/util/libgnunetutil.la \
97 $(GN_LIBINTL)
98gnunet_qr_LDFLAGS= -lzbar
99if HAVE_PNG
100gnunet_qr_LDFLAGS += -lpng
101endif
102
103check_SCRIPTS = \
104 test_crypto_vectors.sh
105
106EXTRA_DIST = \
107 test_crypto_vectors.sh \
108 crypto-test-vectors.json
diff --git a/src/cli/util/crypto-test-vectors.json b/src/cli/util/crypto-test-vectors.json
new file mode 100644
index 000000000..972b62c3e
--- /dev/null
+++ b/src/cli/util/crypto-test-vectors.json
@@ -0,0 +1,56 @@
1{
2 "encoding": "base32crockford",
3 "producer": "GNUnet 0.14.0 git-64ad3b0a1",
4 "vectors": [
5 {
6 "operation": "hash",
7 "input": "91JPRV3F5GG4EKJNDSJQ8",
8 "output": "D0R24RZ1TPASVQ2NY56CT8AJDYZE9ZGDB0GVZ05E9D4YGZQW2RC5YFPQ0Q86EPW836DY7VYQTNFFJT3ZR2K508F4JVS5JNJKYN2MMFR"
9 },
10 {
11 "operation": "ecc_ecdh",
12 "priv1": "TFA439C75RT2JK9V6GTRRXH3QR3QC4SVJ1KBQ4MNY3S338GT6T50",
13 "pub1": "E19WJDA83485BC8EC8RV7FTAK86BESJG1YNYRENEC0JV7XEZ7M80",
14 "priv2": "2DT3B0TMY6VVP56YZKG5ASRSQAEV0GB4QMT9N6CTPDARNJ905APG",
15 "skm": "GY63DCHR6BGV2AKDM44V7A4H4DA0WJC7D5C2R7DXTWC9D83H7XM0PEQKKZ1K2HWMWBSBNPDWXDN7PA1R1WJKVQ2RDTNF1PBXCFHM9QR"
16 },
17 {
18 "operation": "eddsa_key_derivation",
19 "priv": "8QC2VNF8443S5KPNKMB4XMV58BTHWAKZ7SVW5WG3KRB37567XS90",
20 "pub": "3M9KK1WSNM1RTY5P72HKFA264V4B7MVHVJ08Y90CV06DYHV8XPP0"
21 },
22 {
23 "operation": "eddsa_signing",
24 "priv": "5077XJR9AMH4T97ACKFBVBJD0KFENHPV66B2Y1JBSKXBJKNZJ4E0",
25 "pub": "6E2F03JJ8AEDANTTZZ4SBZDFEEZSF8A9DVGTS6VFBCVZQYQ46RRG",
26 "data": "00000300000000000000",
27 "sig": "XCNJGJ96WPDH60YVMH6C74NGQSGJE3BC1TYMGX6BHY5DMZZZKTB373QTXJ507K5EBSG9YS2EYKHCX3ATRQ6P5MY9MXC4ZB1XSZ2X23G"
28 },
29 {
30 "operation": "kdf",
31 "salt": "94KPT83PCNS7J83KC5P78Y8",
32 "ikm": "94KPT83MD1JJ0WV5CDS6AX10D5Q70XBM41NPAY90DNGQ8SBJD5GPR",
33 "ctx": "94KPT83141HPYVKMCNW78833D1TPWTSC41GPRWVF41NPWVVQDRG62WS04XMPWSKF4WG6JVH0EHM6A82J8S1G",
34 "out_len %u\n": 64,
35 "out": "GTMR4QT05Z9WF5HKVG0WK9RPXGHSMHJNW377G9GJXCA8B0FEKPF4D27RJMSJZYWSQNTBJ5EYVV7ZW18B48Z0JVJJ80RHB706Y96Q358"
36 },
37 {
38 "operation": "eddsa_ecdh",
39 "priv_ecdhe": "5FBRFZY942H2PD96NFNYWZKYXCRFY11JWQ59V7G9B4M8EX1KE100",
40 "pub_ecdhe": "GDX7FC01AZYMG0BY0AMHR6E7KCGX9F6SWES16WZ1QWZ2VSYXKH00",
41 "priv_eddsa": "3HYHM9DZQ3D61APDQNBCSKJE452YEP6JK01DWR1J3VZAASFEA570",
42 "pub_eddsa": "87N7PFAHBX97HRE8XYW8KYN64YZDF4FCBR2BZ5SZN3QE3D2BF0R0",
43 "key_material": "QH0RAXXC9RYDEAXKNTAWM0WXJS25RS67H5T252EGA22RA6JTYRFDAEK8CJY85QSYWGYHQXK5Y1SWSRB3P0NXNXYP237EXMXQ3P2WE00"
44 },
45 {
46 "operation": "rsa_blind_signing",
47 "message_hash": "XKQMJ4CNTXBFE1V2WR6JS063J7PZQE4XMB5JH3RS5X0THQ1JQSQ69Y7KDBC9TYRJEZH48MEPY2SF4QHQ4VHXC0YQX5935MQEGP0AX6R",
48 "rsa_public_key": "040000YRN1NVJ68RS6RJF52PGRCQG19ZKWQPSTJX2G7ZDCKSZFE2VW3HHA81YF5C639JHJF5TX8YTEE2FW2WQCG1PTKNBSPPJEJGA032CN3E8QZ27VWY0K6JFT8ZSYWRH2SKDMXW56A4QKY46JJBWJ6T0ZRVBW6S1HTHXVE2RW8MXRW5T801077MDY13N5F8Z1JZVKBJ06TK3S0YPEDBXK0VEHRHEQJ5X5XYKR4KQTFAZNBMKXY8836VCHBXTK4YNX6AJ1CK29SMJH3Z3QRM16A2TNQGFR0HSMV446BF7FMT2E379ZAT5ST4G3BM2NWZYW545S2SW5MG5S6M88XZZ7SKFD48YVXNZ205GGSEYJPVBMR76WG4ZG30WBCPC1N54XE12RMAG81D8C09WG22PKGGDHYXX68N04002",
49 "rsa_private_key": "50W3MTV5F4PP8RBMC4520A1H60X70XB2DHMP6BBBCNWGM81050SKMWKKC452081050RKMVHJ6MVKM06RN1NVJ68RS6RJF52PGRCQG19ZKWQPSTJX2G7ZDCKSZFE2VW3HHA81YF5C639JHJF5TX8YTEE2FW2WQCG1PTKNBSPPJEJGA032CN3E8QZ27VWY0K6JFT8ZSYWRH2SKDMXW56A4QKY46JJBWJ6T0ZRVBW6S1HTHXVE2RW8MXRW5T801077MDY13N5F8Z1JZVKBJ06TK3S0YPEDBXK0VEHRHEQJ5X5XYKR4KQTFAZNBMKXY8836VCHBXTK4YNX6AJ1CK29SMJH3Z3QRM16A2TNQGFR0HSMV446BF7FMT2E379ZAT5ST4G3BM2NWZYW545S2SW5MG5S6M88XZZ7SKFD48YVXNZ205GGSEYJPVBMR76WG4ZG30WBCPC1N54XE12RMAG81D8C09WG22PKGGDHYXX68N5452081050RKMS9K780G009918G2081918G20A8A40M32C9TE1S6JXK1EHJJTTV5F45208186CX74WV118G2081864X6WCHN6WX01P58DEWHJ669P4KS8NM635W0AFWZ5XPEMQ8M1ZVB4YFVVGPZ0WCAJ0FKSB1GTCMCKSEQA7PKKGKZ0Q5V40DPMXAYDNMKMM2G0RK58VJ5ZRHYZ7G4SMKYJ7YFQ648PCVD7F19JH5WZH1MMJZ4HPG7Y6TZ1P8CEMFEVGP7257E71EJ0081SX3FG8X9BT7RCQYWTWG1PMRY87NKKAZCR6VME4BNWHF9FFMY14XYKTQXAX4ZFJ20SPV4AZEMS7NF9JMGB4RJED4M8ZRXY509JGPNDW3Y04ED6S11JVSVX6GKGSTFTPHEEH40TX0NF7ZQ191E8PF1D41E9N227FZSYCVV927PZDFRG1C46BQMNPTX61SQ417W0R72V5K0D997BG8P52M20BA302F40GNMW43CFQF9J59918G2081864X6ACST04002A8A40G20A1H79J34D9P78SBPDS45EQZVX2D6R1GZ6FHKHDG4ABYZ6FCPSMMGZ29ZY5NS8B304D0QBD800A5SM3D8S92WKS3KFWFXE8X597TNJBR94BGNCFHY8TV63KQZ0RFMRTPHFA2XNFX2V4KECZNTHGKZNJTWH8051XP6FJJ6700A5KWMH24CK1KF9XVH2ATQJ4F1ZJZQM00A00ESTVKM5N58K5FN5TW34B1H1Q1CWRZXJ9QMBG0QKHXHZMFYZSN9ERV59935716NGSX9GBB3R9BY32TBTAJ7K0N391ATSE5263X5NKVDH7XCF1PF0WRTTJYBAJBQWVGJ8P7RGVWB27Q3S4AJJ55FS2T9K341EHATHJZQQTR0JWP5E4NQHR4GN60QMK2SY0VJM56N0NHJXRGAGJW3S9ABJ7M4TAV6YRJJ2H040G2GC9TE0RK4E9T03CET00DAJDXJ1NF511J69JMDDSVARPSFSS6AJTRMVXD10NVA4Z162ER74WNH0J6H2RTA9C9MZM4TEBP8P7AF0NANBH4XZJCNDZV7BEAMJ6R363GHZKGBR0HH1SATGWNJWGW2961MRFPX7S0RJK7CWYE7EX1XQ2683TENRPDKV29D1F1RNDD6P04MZTKSH5YMEZPKGEDRJZXXM9918G2081864X72C9J74X01ZXF256C681JDWRRG7T4AC9JRHP54YM65X9AT17YGC3G4569ZKBQEZ219Y7JG4V10F4AW7Q1XKGPTW3Y3X0WCTB06HM249Q094VHEYD4BTEQ2DF334W8G3VEB7N1CHCMPZEVVTR0XWQSNV6MBJRF5MBY6Z148YA36YA61EXA28PHE3KSN1M4HVF7B06JD736TSK9GC9CAG8F0MMGM81040M32EKN64S3JEG0YCC3PHPNBZAGQ2WE8HJHM28B049N2MQ94G8VPXNHG43C6ADB44DE1DK8ASMYTSXZWMAYKN1SS2GVFTVH8Q4N3TTJ3BKA61Y93QE17XNRF3S0CSSQTY3SVVAFHDA9APFFSMRYD67N4DXQ1X42NA270VF6H0MCRQ87JKVBQAB0CH2WH7RHYMCQ4KN50M2NEFE1YA6F2N2DG7Z9JA8A40G20A8A40G2J2H054500",
50 "blinding_key_secret": "3SWF49XZPHQMENTSBZQR7Z0B8ZSZ2JRARE79Q4VXZMQ7W6QABXMG",
51 "blinded_message": "3KHKZJZ30ABB4E56MA2V0EQWGCWH0QQG9P2ZHYHR186C5HZXJMM4N9WXAQTKS94QSV9Y17GGNXN5MB1PZZFG7Q0FY88QPKKRG4MYCPSMTZK5W59R0MJVNJ4P4AQM96TDG5W7RV8GSNR1QQZ1GNHW3CX6D6ZRTMXB2NKB5SSYTDJS79F5ZFBRZ4HVED9JBBPWSR79KVV5QQ4APBGHBCKGMF9NJJS53A1BVYHDEVYAGFYF2SNEP827ZP50FKJ5GKGV8NQ15ESEZ69AT7GJG0T3TZVENY2YN9CVR98W3BKEZ53J7VTANARG8SJS8AMJQ7S23P5HRJ7XE9KTNRNXKH49MXV9JHHYE5535N7AGWEKR47SBCGNF44Z7XJ9RV5BQV12ZRJKN4HBZQHDNCMH3QKX9Z6G64",
52 "blinded_sig": "ND1V807BK0G73SDXN582BP3Q21MWF4A76EGWD0KA3XGJAWPSVHNHKA44931ZRB9M76SYAFD8ZPTG3A7FH5G2CWGX76VXTCDX5XNRW7EEBNMPDAQ0ZEKF6AHP872SKCGRH89SK4NGC57M8BRA3ZRPDDT9XCBG3XY02VQH4Z0F39DPBS48K0EBMK7B9S3X6QDNR5ND5MV0G7G7T3VPKZRW94MQBKPY1T6K53MQGG4PV81D9YEWNRM3WE04NNQREYDA5ETVDWQ5ZCYV9HF4ZCMWVVGWDBDH732JA3NKZ2B8QK0E6XS0Y4GGGQJS6HFQ4PATGK3TS5GHJEPDF3A6XAFNJQV99CSJW7V1NC504NTQ5NJ8KAVC1758MBBV3SS2BND4YHF0Y4NWJNVH3STV166YWFKR8W",
53 "sig": "EC5MVSPGQMM96N2VT4R2G5104E61V8RY4PR6AK9F614TVVEN7D152T0DP97CDTRDDSQGBV4GZWXQPM90SW30R2RAKKHNDCXHQFAMRSW1XCBEKVKBGC6FP0AQY9S37NVR01VJ2WVX8PN29H2ZFFQBQ9JK96GTJZ3B7DD583S8Y93GH5KWEM41CZJ73QCRT1A2AGVXX5ACFR0T448MC81QB4EGCKP5Z96VCX6RPDD5S9A4295M0E9PPQJCN5G5JKWKG17HWEDF4A26ZMD8YW27EQBZ69GSEZX4PWEV7AXFGG5X0RPKCQEPCX7XDY6NXJ1E2FZBX259RDRCFNDAZS80T0DHD9NVE73QDDESZYEZTM1TM669GHPN8AF4QV8DNW7SFZZKJ67FWR8CZC0PWTEN4ZPTRM"
54 }
55 ]
56}
diff --git a/src/cli/util/gnunet-base32.c b/src/cli/util/gnunet-base32.c
new file mode 100644
index 000000000..209741740
--- /dev/null
+++ b/src/cli/util/gnunet-base32.c
@@ -0,0 +1,155 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 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 util/gnunet-base32.c
23 * @brief tool to encode/decode from/to the Crockford Base32 encoding GNUnet uses
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30
31/**
32 * The main function of gnunet-base32
33 *
34 * @param argc number of arguments from the command line
35 * @param argv command line arguments
36 * @return 0 ok, 1 on error
37 */
38int
39main (int argc,
40 char *const *argv)
41{
42 int decode = 0;
43 const struct GNUNET_GETOPT_CommandLineOption options[] = {
44 GNUNET_GETOPT_option_flag ('d',
45 "decode",
46 gettext_noop (
47 "run decoder modus, otherwise runs as encoder"),
48 &decode),
49 GNUNET_GETOPT_option_help ("Crockford base32 encoder/decoder"),
50 GNUNET_GETOPT_option_version (PACKAGE_VERSION),
51 GNUNET_GETOPT_OPTION_END
52 };
53 int ret;
54 char *in;
55 unsigned int in_size;
56 ssize_t iret;
57 char *out;
58 size_t out_size;
59
60 if (GNUNET_OK !=
61 GNUNET_STRINGS_get_utf8_args (argc, argv,
62 &argc, &argv))
63 return 2;
64 ret = GNUNET_GETOPT_run ("gnunet-base32",
65 options,
66 argc,
67 argv);
68 if (ret < 0)
69 return 1;
70 if (0 == ret)
71 return 0;
72 in_size = 0;
73 in = NULL;
74 iret = 1;
75 while (iret > 0)
76 {
77 /* read in blocks of 4k */
78 char buf[4092];
79
80 iret = read (0,
81 buf,
82 sizeof (buf));
83 if (iret < 0)
84 {
85 GNUNET_free (in);
86 return 2;
87 }
88 if (iret > 0)
89 {
90 if (iret + in_size < in_size)
91 {
92 GNUNET_break (0);
93 GNUNET_free (in);
94 return 1;
95 }
96 GNUNET_array_grow (in,
97 in_size,
98 in_size + iret);
99 memcpy (&in[in_size - iret],
100 buf,
101 iret);
102 }
103 }
104 if (decode)
105 {
106 /* This formula can overestimate by 1 byte, so we try both
107 out_size and out_size-1 below */
108 out_size = in_size * 5 / 8;
109 out = GNUNET_malloc (out_size);
110 if ( (GNUNET_OK !=
111 GNUNET_STRINGS_string_to_data (in,
112 in_size,
113 out,
114 out_size)) &&
115 (out_size > 0) )
116 {
117 out_size--;
118 if (GNUNET_OK !=
119 GNUNET_STRINGS_string_to_data (in,
120 in_size,
121 out,
122 out_size))
123 {
124 GNUNET_free (out);
125 GNUNET_free (in);
126 return 3;
127 }
128 }
129 }
130 else
131 {
132 out = GNUNET_STRINGS_data_to_string_alloc (in,
133 in_size);
134 out_size = strlen (out);
135 }
136 {
137 size_t pos = 0;
138
139 while (pos < out_size)
140 {
141 iret = write (1,
142 &out[pos],
143 out_size - pos);
144 if (iret <= 0)
145 return 4;
146 pos += iret;
147 }
148 }
149 GNUNET_free (out);
150 GNUNET_free_nz ((void *) argv);
151 return 0;
152}
153
154
155/* end of gnunet-uri.c */
diff --git a/src/cli/util/gnunet-config-diff.c b/src/cli/util/gnunet-config-diff.c
new file mode 100644
index 000000000..e1e3ffd5d
--- /dev/null
+++ b/src/cli/util/gnunet-config-diff.c
@@ -0,0 +1,24 @@
1
2#include "platform.h"
3#include <gnunet_util_lib.h>
4
5int
6main (int argc, char **argv)
7{
8 struct GNUNET_CONFIGURATION_Handle *i1;
9 struct GNUNET_CONFIGURATION_Handle *i2;
10
11 if (argc != 3)
12 {
13 fprintf (stderr, "Invoke using `%s DEFAULTS-IN DIFFS'\n", argv[0]);
14 return 1;
15 }
16 i1 = GNUNET_CONFIGURATION_create ();
17 i2 = GNUNET_CONFIGURATION_create ();
18 if ((GNUNET_OK != GNUNET_CONFIGURATION_load (i1, argv[1])) ||
19 (GNUNET_OK != GNUNET_CONFIGURATION_load (i2, argv[2])))
20 return 1;
21 if (GNUNET_OK != GNUNET_CONFIGURATION_write_diffs (i1, i2, argv[2]))
22 return 2;
23 return 0;
24}
diff --git a/src/cli/util/gnunet-config.c b/src/cli/util/gnunet-config.c
new file mode 100644
index 000000000..714c683dd
--- /dev/null
+++ b/src/cli/util/gnunet-config.c
@@ -0,0 +1,206 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2021 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 util/gnunet-config.c
23 * @brief tool to access and manipulate GNUnet configuration files
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30
31/**
32 * Backend to check if the respective plugin is
33 * loadable. NULL if no check is to be performed.
34 * The value is the "basename" of the plugin to load.
35 */
36static char *backend_check;
37
38
39/**
40 * If printing the value of CFLAGS has been requested.
41 */
42static int cflags;
43
44/**
45 * Check if this is an experimental build
46 */
47static int is_experimental;
48
49
50/**
51 * If printing the value of LIBS has been requested.
52 */
53static int libs;
54
55
56/**
57 * If printing the value of PREFIX has been requested.
58 */
59static int prefix;
60
61
62/**
63 * Print each option in a given section.
64 * Main task to run to perform operations typical for
65 * gnunet-config as per the configuration settings
66 * given in @a cls.
67 *
68 * @param cls closure with the `struct GNUNET_CONFIGURATION_ConfigSettings`
69 * @param args remaining command-line arguments
70 * @param cfgfile name of the configuration file used (for saving,
71 * can be NULL!)
72 * @param cfg configuration
73 */
74static void
75run (void *cls,
76 char *const *args,
77 const char *cfgfile,
78 const struct GNUNET_CONFIGURATION_Handle *cfg)
79{
80 struct GNUNET_CONFIGURATION_ConfigSettings *cs = cls;
81
82 if (1 == is_experimental)
83 {
84#ifdef GNUNET_EXPERIMENTAL
85 cs->global_ret = 0;
86#else
87 cs->global_ret = 1;
88#endif
89 return;
90 }
91 if (1 == cflags || 1 == libs || 1 == prefix)
92 {
93 char *prefixdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_PREFIX);
94 char *libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
95
96 if (1 == cflags)
97 {
98 fprintf (stdout, "-I%sinclude\n", prefixdir);
99 }
100 if (1 == libs)
101 {
102 fprintf (stdout, "-L%s -lgnunetutil\n", libdir);
103 }
104 if (1 == prefix)
105 {
106 fprintf (stdout, "%s\n", prefixdir);
107 }
108 cs->global_ret = 0;
109 GNUNET_free (prefixdir);
110 GNUNET_free (libdir);
111 return;
112 }
113 if (NULL != backend_check)
114 {
115 char *name;
116
117 GNUNET_asprintf (&name,
118 "libgnunet_plugin_%s",
119 backend_check);
120 cs->global_ret = (GNUNET_OK ==
121 GNUNET_PLUGIN_test (name)) ? 0 : 77;
122 GNUNET_free (name);
123 return;
124 }
125 GNUNET_CONFIGURATION_config_tool_run (cs,
126 args,
127 cfgfile,
128 cfg);
129}
130
131
132/**
133 * Program to manipulate configuration files.
134 *
135 * @param argc number of arguments from the command line
136 * @param argv command line arguments
137 * @return 0 ok, 1 on error
138 */
139int
140main (int argc,
141 char *const *argv)
142{
143 struct GNUNET_CONFIGURATION_ConfigSettings cs = {
144 .api_version = GNUNET_UTIL_VERSION,
145 .global_ret = EXIT_SUCCESS
146 };
147 struct GNUNET_GETOPT_CommandLineOption options[] = {
148 GNUNET_GETOPT_option_exclusive (
149 GNUNET_GETOPT_option_string (
150 'b',
151 "supported-backend",
152 "BACKEND",
153 gettext_noop (
154 "test if the current installation supports the specified BACKEND"),
155 &backend_check)),
156 GNUNET_GETOPT_option_flag (
157 'C',
158 "cflags",
159 gettext_noop (
160 "Provide an appropriate value for CFLAGS to applications building on top of GNUnet"),
161 &cflags),
162 GNUNET_GETOPT_option_flag (
163 'E',
164 "is-experimental",
165 gettext_noop ("Is this an experimental build of GNUnet"),
166 &is_experimental),
167 GNUNET_GETOPT_option_flag (
168 'j',
169 "libs",
170 gettext_noop (
171 "Provide an appropriate value for LIBS to applications building on top of GNUnet"),
172 &libs),
173 GNUNET_GETOPT_option_flag (
174 'p',
175 "prefix",
176 gettext_noop (
177 "Provide the path under which GNUnet was installed"),
178 &prefix),
179 GNUNET_CONFIGURATION_CONFIG_OPTIONS (&cs),
180 GNUNET_GETOPT_OPTION_END
181 };
182 enum GNUNET_GenericReturnValue ret;
183
184 if (GNUNET_OK !=
185 GNUNET_STRINGS_get_utf8_args (argc, argv,
186 &argc, &argv))
187 return EXIT_FAILURE;
188 ret =
189 GNUNET_PROGRAM_run (argc,
190 argv,
191 "gnunet-config [OPTIONS]",
192 gettext_noop ("Manipulate GNUnet configuration files"),
193 options,
194 &run,
195 &cs);
196 GNUNET_free_nz ((void *) argv);
197 GNUNET_CONFIGURATION_config_settings_free (&cs);
198 if (GNUNET_NO == ret)
199 return 0;
200 if (GNUNET_SYSERR == ret)
201 return EXIT_INVALIDARGUMENT;
202 return cs.global_ret;
203}
204
205
206/* end of gnunet-config.c */
diff --git a/src/cli/util/gnunet-crypto-tvg.c b/src/cli/util/gnunet-crypto-tvg.c
new file mode 100644
index 000000000..721177eda
--- /dev/null
+++ b/src/cli/util/gnunet-crypto-tvg.c
@@ -0,0 +1,1608 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 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 util/gnunet-crypto-tgv.c
23 * @brief Generate test vectors for cryptographic operations.
24 * @author Florian Dold
25 *
26 * Note that this program shouldn't depend on code in src/json/,
27 * so we're using raw jansson and no GNUnet JSON helpers.
28 *
29 * Test vectors have the following format (TypeScript pseudo code):
30 *
31 * interface TestVectorFile {
32 * encoding: "base32crockford";
33 * producer?: string;
34 * vectors: TestVector[];
35 * }
36 *
37 * enum Operation {
38 * Hash("hash"),
39 * ...
40 * }
41 *
42 * interface TestVector {
43 * operation: Operation;
44 * // Inputs for the operation
45 * [ k: string]: string | number;
46 * };
47 *
48 *
49 */
50
51#include "platform.h"
52#include "gnunet_util_lib.h"
53#include "gnunet_signatures.h"
54#include "gnunet_testing_lib.h"
55#include <jansson.h>
56#include <gcrypt.h>
57
58GNUNET_NETWORK_STRUCT_BEGIN
59
60/**
61 * Sample signature struct.
62 *
63 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TEST
64 */
65struct TestSignatureDataPS
66{
67 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
68 uint32_t testval;
69};
70
71GNUNET_NETWORK_STRUCT_END
72
73
74/**
75 * Should we verify or output test vectors?
76 */
77static int verify_flag = GNUNET_NO;
78
79
80/**
81 * Global exit code.
82 */
83static int global_ret = 0;
84
85
86/**
87 * Create a fresh test vector for a given operation label.
88 *
89 * @param vecs array of vectors to append the new vector to
90 * @param vecname label for the operation of the vector
91 * @returns the fresh test vector
92 */
93static json_t *
94vec_for (json_t *vecs, const char *vecname)
95{
96 json_t *t = json_object ();
97
98 json_object_set_new (t,
99 "operation",
100 json_string (vecname));
101 json_array_append_new (vecs, t);
102 return t;
103}
104
105
106/**
107 * Add a base32crockford encoded value
108 * to a test vector.
109 *
110 * @param vec test vector to add to
111 * @param label label for the value
112 * @param data data to add
113 * @param size size of data
114 */
115static void
116d2j (json_t *vec,
117 const char *label,
118 const void *data,
119 size_t size)
120{
121 char *buf;
122 json_t *json;
123
124 buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
125 json = json_string (buf);
126 GNUNET_free (buf);
127 GNUNET_break (NULL != json);
128
129 json_object_set_new (vec, label, json);
130}
131
132
133/**
134 * Add a number to a test vector.
135 *
136 * @param vec test vector to add to
137 * @param label label for the value
138 * @param data data to add
139 * @param size size of data
140 */
141static void
142uint2j (json_t *vec,
143 const char *label,
144 unsigned int num)
145{
146 json_t *json = json_integer (num);
147
148 json_object_set_new (vec, label, json);
149}
150
151
152static int
153expect_data_fixed (json_t *vec,
154 const char *name,
155 void *data,
156 size_t expect_len)
157{
158 const char *s = json_string_value (json_object_get (vec, name));
159
160 if (NULL == s)
161 return GNUNET_NO;
162
163 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s,
164 strlen (s),
165 data,
166 expect_len))
167 return GNUNET_NO;
168 return GNUNET_OK;
169}
170
171
172static int
173expect_data_dynamic (json_t *vec,
174 const char *name,
175 void **data,
176 size_t *ret_len)
177{
178 const char *s = json_string_value (json_object_get (vec, name));
179 char *tmp;
180 size_t len;
181
182 if (NULL == s)
183 return GNUNET_NO;
184
185 len = (strlen (s) * 5) / 8;
186 if (NULL != ret_len)
187 *ret_len = len;
188 tmp = GNUNET_malloc (len);
189
190 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, strlen (s), tmp, len))
191 {
192 GNUNET_free (tmp);
193 return GNUNET_NO;
194 }
195 *data = tmp;
196 return GNUNET_OK;
197}
198
199
200/**
201 * Check a single vector.
202 *
203 * @param operation operator of the vector
204 * @param vec the vector, a JSON object.
205 *
206 * @returns GNUNET_OK if the vector is okay
207 */
208static int
209checkvec (const char *operation,
210 json_t *vec)
211{
212 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
213 "checking %s\n", operation);
214
215 if (0 == strcmp (operation, "hash"))
216 {
217 void *data;
218 size_t data_len;
219 struct GNUNET_HashCode hash_out;
220 struct GNUNET_HashCode hc;
221
222 if (GNUNET_OK != expect_data_dynamic (vec,
223 "input",
224 &data,
225 &data_len))
226 {
227 GNUNET_break (0);
228 return GNUNET_SYSERR;
229 }
230 if (GNUNET_OK != expect_data_fixed (vec,
231 "output",
232 &hash_out,
233 sizeof (hash_out)))
234 {
235 GNUNET_free (data);
236 GNUNET_break (0);
237 return GNUNET_NO;
238 }
239
240 GNUNET_CRYPTO_hash (data, data_len, &hc);
241
242 if (0 != GNUNET_memcmp (&hc, &hash_out))
243 {
244 GNUNET_free (data);
245 GNUNET_break (0);
246 return GNUNET_NO;
247 }
248 GNUNET_free (data);
249 }
250 else if (0 == strcmp (operation, "ecc_ecdh"))
251 {
252 struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
253 struct GNUNET_CRYPTO_EcdhePublicKey pub1;
254 struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
255 struct GNUNET_HashCode skm;
256 struct GNUNET_HashCode skm_comp;
257
258 if (GNUNET_OK != expect_data_fixed (vec,
259 "priv1",
260 &priv1,
261 sizeof (priv1)))
262 {
263 GNUNET_break (0);
264 return GNUNET_NO;
265 }
266 if (GNUNET_OK != expect_data_fixed (vec,
267 "priv2",
268 &priv2,
269 sizeof (priv2)))
270 {
271 GNUNET_break (0);
272 return GNUNET_NO;
273 }
274 if (GNUNET_OK != expect_data_fixed (vec,
275 "pub1",
276 &pub1,
277 sizeof (pub1)))
278 {
279 GNUNET_break (0);
280 return GNUNET_NO;
281 }
282 if (GNUNET_OK != expect_data_fixed (vec,
283 "skm",
284 &skm,
285 sizeof (skm)))
286 {
287 GNUNET_break (0);
288 return GNUNET_NO;
289 }
290 GNUNET_assert (GNUNET_OK ==
291 GNUNET_CRYPTO_ecc_ecdh (&priv2,
292 &pub1,
293 &skm_comp));
294 if (0 != GNUNET_memcmp (&skm, &skm_comp))
295 {
296 GNUNET_break (0);
297 return GNUNET_NO;
298 }
299 }
300 else if (0 == strcmp (operation, "eddsa_key_derivation"))
301 {
302 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
303 struct GNUNET_CRYPTO_EddsaPublicKey pub;
304 struct GNUNET_CRYPTO_EddsaPublicKey pub_comp;
305
306 if (GNUNET_OK != expect_data_fixed (vec,
307 "priv",
308 &priv,
309 sizeof (priv)))
310 {
311 GNUNET_break (0);
312 return GNUNET_NO;
313 }
314
315 if (GNUNET_OK != expect_data_fixed (vec,
316 "pub",
317 &pub,
318 sizeof (pub)))
319 {
320 GNUNET_break (0);
321 return GNUNET_NO;
322 }
323
324 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
325 &pub_comp);
326 if (0 != GNUNET_memcmp (&pub, &pub_comp))
327 {
328 GNUNET_break (0);
329 return GNUNET_NO;
330 }
331
332 }
333 else if (0 == strcmp (operation, "eddsa_signing"))
334 {
335 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
336 struct GNUNET_CRYPTO_EddsaPublicKey pub;
337 struct TestSignatureDataPS data = { 0 };
338 struct GNUNET_CRYPTO_EddsaSignature sig;
339 struct GNUNET_CRYPTO_EddsaSignature sig_comp;
340
341 if (GNUNET_OK != expect_data_fixed (vec,
342 "priv",
343 &priv,
344 sizeof (priv)))
345 {
346 GNUNET_break (0);
347 return GNUNET_NO;
348 }
349
350 if (GNUNET_OK != expect_data_fixed (vec,
351 "pub",
352 &pub,
353 sizeof (pub)))
354 {
355 GNUNET_break (0);
356 return GNUNET_NO;
357 }
358
359 if (GNUNET_OK != expect_data_fixed (vec,
360 "data",
361 &data,
362 sizeof (data)))
363 {
364 GNUNET_break (0);
365 return GNUNET_NO;
366 }
367
368 if (GNUNET_OK != expect_data_fixed (vec,
369 "sig",
370 &sig,
371 sizeof (sig)))
372 {
373 GNUNET_break (0);
374 return GNUNET_NO;
375 }
376
377 GNUNET_CRYPTO_eddsa_sign (&priv,
378 &data,
379 &sig_comp);
380 GNUNET_assert (GNUNET_OK ==
381 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST,
382 &data,
383 &sig,
384 &pub));
385 if (0 != GNUNET_memcmp (&sig, &sig_comp))
386 {
387 GNUNET_break (0);
388 return GNUNET_NO;
389 }
390 }
391 else if (0 == strcmp (operation, "kdf"))
392 {
393 size_t out_len;
394 void *out;
395 size_t out_len_comp;
396 void *out_comp;
397 void *ikm;
398 size_t ikm_len;
399 void *salt;
400 size_t salt_len;
401 void *ctx;
402 size_t ctx_len;
403
404 if (GNUNET_OK != expect_data_dynamic (vec,
405 "out",
406 &out,
407 &out_len))
408 {
409 GNUNET_break (0);
410 return GNUNET_SYSERR;
411 }
412
413 out_len_comp = out_len;
414 out_comp = GNUNET_malloc (out_len_comp);
415
416 if (GNUNET_OK != expect_data_dynamic (vec,
417 "ikm",
418 &ikm,
419 &ikm_len))
420 {
421 GNUNET_free (out);
422 GNUNET_free (out_comp);
423 GNUNET_break (0);
424 return GNUNET_SYSERR;
425 }
426
427 if (GNUNET_OK != expect_data_dynamic (vec,
428 "salt",
429 &salt,
430 &salt_len))
431 {
432 GNUNET_free (out);
433 GNUNET_free (out_comp);
434 GNUNET_free (ikm);
435 GNUNET_break (0);
436 return GNUNET_SYSERR;
437 }
438
439 if (GNUNET_OK != expect_data_dynamic (vec,
440 "ctx",
441 &ctx,
442 &ctx_len))
443 {
444 GNUNET_free (out);
445 GNUNET_free (out_comp);
446 GNUNET_free (ikm);
447 GNUNET_free (salt);
448 GNUNET_break (0);
449 return GNUNET_SYSERR;
450 }
451
452 GNUNET_assert (GNUNET_OK ==
453 GNUNET_CRYPTO_kdf (out_comp,
454 out_len_comp,
455 salt,
456 salt_len,
457 ikm,
458 ikm_len,
459 ctx,
460 ctx_len,
461 NULL));
462
463 if (0 != memcmp (out, out_comp, out_len))
464 {
465 GNUNET_free (out);
466 GNUNET_free (out_comp);
467 GNUNET_free (ikm);
468 GNUNET_free (salt);
469 GNUNET_free (ctx);
470 GNUNET_break (0);
471 return GNUNET_NO;
472 }
473 GNUNET_free (out);
474 GNUNET_free (out_comp);
475 GNUNET_free (ikm);
476 GNUNET_free (salt);
477 GNUNET_free (ctx);
478 }
479 else if (0 == strcmp (operation, "eddsa_ecdh"))
480 {
481 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe;
482 struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe;
483 struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa;
484 struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa;
485 struct GNUNET_HashCode key_material;
486 struct GNUNET_HashCode key_material_comp;
487
488 if (GNUNET_OK != expect_data_fixed (vec,
489 "priv_ecdhe",
490 &priv_ecdhe,
491 sizeof (priv_ecdhe)))
492 {
493 GNUNET_break (0);
494 return GNUNET_NO;
495 }
496
497 if (GNUNET_OK != expect_data_fixed (vec,
498 "pub_ecdhe",
499 &pub_ecdhe,
500 sizeof (pub_ecdhe)))
501 {
502 GNUNET_break (0);
503 return GNUNET_NO;
504 }
505
506 if (GNUNET_OK != expect_data_fixed (vec,
507 "priv_eddsa",
508 &priv_eddsa,
509 sizeof (priv_eddsa)))
510 {
511 GNUNET_break (0);
512 return GNUNET_NO;
513 }
514
515 if (GNUNET_OK != expect_data_fixed (vec,
516 "pub_eddsa",
517 &pub_eddsa,
518 sizeof (pub_eddsa)))
519 {
520 GNUNET_break (0);
521 return GNUNET_NO;
522 }
523
524 if (GNUNET_OK != expect_data_fixed (vec,
525 "key_material",
526 &key_material,
527 sizeof (key_material)))
528 {
529 GNUNET_break (0);
530 return GNUNET_NO;
531 }
532
533 GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe,
534 &pub_eddsa,
535 &key_material_comp);
536
537 if (0 != GNUNET_memcmp (&key_material,
538 &key_material_comp))
539 {
540 GNUNET_break (0);
541 return GNUNET_NO;
542 }
543 }
544 else if (0 == strcmp (operation, "rsa_blind_signing"))
545 {
546 struct GNUNET_CRYPTO_RsaPrivateKey *skey;
547 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
548 struct GNUNET_HashCode message_hash;
549 struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
550 struct GNUNET_CRYPTO_RsaSignature *blinded_sig;
551 struct GNUNET_CRYPTO_RsaSignature *sig;
552 struct GNUNET_CRYPTO_RsaBlindedMessage bm;
553 struct GNUNET_CRYPTO_RsaBlindedMessage bm_comp;
554 void *public_enc_data;
555 size_t public_enc_len;
556 void *secret_enc_data;
557 size_t secret_enc_len;
558 void *sig_enc_data;
559 size_t sig_enc_length;
560 void *sig_enc_data_comp;
561 size_t sig_enc_length_comp;
562
563 if (GNUNET_OK !=
564 expect_data_fixed (vec,
565 "message_hash",
566 &message_hash,
567 sizeof (message_hash)))
568 {
569 GNUNET_break (0);
570 return GNUNET_SYSERR;
571 }
572
573 if (GNUNET_OK !=
574 expect_data_fixed (vec,
575 "blinding_key_secret",
576 &bks,
577 sizeof (bks)))
578 {
579 GNUNET_break (0);
580 return GNUNET_SYSERR;
581 }
582
583 if (GNUNET_OK !=
584 expect_data_dynamic (vec,
585 "blinded_message",
586 &bm.blinded_msg,
587 &bm.blinded_msg_size))
588 {
589 GNUNET_break (0);
590 return GNUNET_SYSERR;
591 }
592 if (GNUNET_OK !=
593 expect_data_dynamic (vec,
594 "rsa_public_key",
595 &public_enc_data,
596 &public_enc_len))
597 {
598 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
599 GNUNET_break (0);
600 return GNUNET_SYSERR;
601 }
602 if (GNUNET_OK !=
603 expect_data_dynamic (vec,
604 "rsa_private_key",
605 &secret_enc_data,
606 &secret_enc_len))
607 {
608 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
609 GNUNET_free (public_enc_data);
610 GNUNET_break (0);
611 return GNUNET_SYSERR;
612 }
613 if (GNUNET_OK !=
614 expect_data_dynamic (vec,
615 "sig",
616 &sig_enc_data,
617 &sig_enc_length))
618 {
619 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
620 GNUNET_free (public_enc_data);
621 GNUNET_free (secret_enc_data);
622 GNUNET_break (0);
623 return GNUNET_SYSERR;
624 }
625
626 pkey = GNUNET_CRYPTO_rsa_public_key_decode (public_enc_data,
627 public_enc_len);
628 GNUNET_assert (NULL != pkey);
629 skey = GNUNET_CRYPTO_rsa_private_key_decode (secret_enc_data,
630 secret_enc_len);
631 GNUNET_assert (NULL != skey);
632
633 GNUNET_assert (GNUNET_YES ==
634 GNUNET_CRYPTO_rsa_blind (&message_hash,
635 sizeof (message_hash),
636 &bks,
637 pkey,
638 &bm_comp));
639 if ( (bm.blinded_msg_size !=
640 bm_comp.blinded_msg_size) ||
641 (0 != memcmp (bm.blinded_msg,
642 bm_comp.blinded_msg,
643 bm.blinded_msg_size)) )
644 {
645 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
646 GNUNET_CRYPTO_rsa_blinded_message_free (&bm_comp);
647 GNUNET_free (public_enc_data);
648 GNUNET_free (secret_enc_data);
649 GNUNET_free (sig_enc_data);
650 GNUNET_CRYPTO_rsa_private_key_free (skey);
651 GNUNET_CRYPTO_rsa_public_key_free (pkey);
652 GNUNET_break (0);
653 return GNUNET_NO;
654 }
655 blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey,
656 &bm);
657 sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig,
658 &bks,
659 pkey);
660 GNUNET_assert (GNUNET_YES ==
661 GNUNET_CRYPTO_rsa_verify (&message_hash,
662 sizeof (message_hash),
663 sig,
664 pkey));
665 GNUNET_free (public_enc_data);
666 public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
667 &public_enc_data);
668 sig_enc_length_comp = GNUNET_CRYPTO_rsa_signature_encode (sig,
669 &sig_enc_data_comp);
670
671 if ( (sig_enc_length != sig_enc_length_comp) ||
672 (0 != memcmp (sig_enc_data, sig_enc_data_comp, sig_enc_length) ))
673 {
674 GNUNET_CRYPTO_rsa_signature_free (blinded_sig);
675 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
676 GNUNET_CRYPTO_rsa_blinded_message_free (&bm_comp);
677 GNUNET_free (public_enc_data);
678 GNUNET_free (secret_enc_data);
679 GNUNET_free (sig_enc_data);
680 GNUNET_free (sig_enc_data_comp);
681 GNUNET_CRYPTO_rsa_private_key_free (skey);
682 GNUNET_CRYPTO_rsa_signature_free (sig);
683 GNUNET_CRYPTO_rsa_public_key_free (pkey);
684 GNUNET_break (0);
685 return GNUNET_NO;
686 }
687 GNUNET_CRYPTO_rsa_signature_free (blinded_sig);
688 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
689 GNUNET_CRYPTO_rsa_blinded_message_free (&bm_comp);
690 GNUNET_free (public_enc_data);
691 GNUNET_free (secret_enc_data);
692 GNUNET_free (sig_enc_data);
693 GNUNET_free (sig_enc_data_comp);
694 GNUNET_CRYPTO_rsa_signature_free (sig);
695 GNUNET_CRYPTO_rsa_public_key_free (pkey);
696 GNUNET_CRYPTO_rsa_private_key_free (skey);
697 }
698 else if (0 == strcmp (operation, "cs_blind_signing"))
699 {
700 struct GNUNET_CRYPTO_CsPrivateKey priv;
701 struct GNUNET_CRYPTO_CsPublicKey pub;
702 struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
703 struct GNUNET_CRYPTO_CsRSecret r_priv[2];
704 struct GNUNET_CRYPTO_CsRPublic r_pub[2];
705 struct GNUNET_CRYPTO_CSPublicRPairP r_pub_blind;
706 struct GNUNET_CRYPTO_CsC c[2];
707 struct GNUNET_CRYPTO_CsS signature_scalar;
708 struct GNUNET_CRYPTO_CsBlindS blinded_s;
709 struct GNUNET_CRYPTO_CsSignature sig;
710 struct GNUNET_CRYPTO_CsSessionNonce snonce;
711 struct GNUNET_CRYPTO_CsBlindingNonce bnonce;
712 struct GNUNET_HashCode message_hash;
713 unsigned int b;
714
715 if (GNUNET_OK != expect_data_fixed (vec,
716 "message_hash",
717 &message_hash,
718 sizeof (message_hash)))
719 {
720 GNUNET_break (0);
721 return GNUNET_SYSERR;
722 }
723 if (GNUNET_OK != expect_data_fixed (vec,
724 "cs_public_key",
725 &pub,
726 sizeof (pub)))
727 {
728 GNUNET_break (0);
729 return GNUNET_SYSERR;
730 }
731
732 if (GNUNET_OK !=
733 expect_data_fixed (vec,
734 "cs_private_key",
735 &priv,
736 sizeof (priv)))
737 {
738 GNUNET_break (0);
739 return GNUNET_SYSERR;
740 }
741 if (GNUNET_OK !=
742 expect_data_fixed (vec,
743 "cs_nonce",
744 &snonce,
745 sizeof (snonce)))
746 {
747 GNUNET_break (0);
748 return GNUNET_SYSERR;
749 }
750 /* historically, the tvg used the same nonce for
751 both, which is HORRIBLE for production, but
752 maybe OK for TVG... */
753 memcpy (&bnonce,
754 &snonce,
755 sizeof (snonce));
756 if (GNUNET_OK !=
757 expect_data_fixed (vec,
758 "cs_r_priv_0",
759 &r_priv[0],
760 sizeof (r_priv[0])))
761 {
762 GNUNET_break (0);
763 return GNUNET_SYSERR;
764 }
765 if (GNUNET_OK != expect_data_fixed (vec,
766 "cs_r_priv_1",
767 &r_priv[1],
768 sizeof (r_priv[1])))
769 {
770 GNUNET_break (0);
771 return GNUNET_SYSERR;
772 }
773 if (GNUNET_OK != expect_data_fixed (vec,
774 "cs_r_pub_0",
775 &r_pub[0],
776 sizeof (r_pub[0])))
777 {
778 GNUNET_break (0);
779 return GNUNET_SYSERR;
780 }
781 if (GNUNET_OK != expect_data_fixed (vec,
782 "cs_r_pub_1",
783 &r_pub[1],
784 sizeof (r_pub[1])))
785 {
786 GNUNET_break (0);
787 return GNUNET_SYSERR;
788 }
789
790 if (GNUNET_OK != expect_data_fixed (vec,
791 "cs_bs_alpha_0",
792 &bs[0].alpha,
793 sizeof (bs[0].alpha)))
794 {
795 GNUNET_break (0);
796 return GNUNET_SYSERR;
797 }
798 if (GNUNET_OK != expect_data_fixed (vec,
799 "cs_bs_alpha_1",
800 &bs[1].alpha,
801 sizeof (bs[1].alpha)))
802 {
803 GNUNET_break (0);
804 return GNUNET_SYSERR;
805 }
806 if (GNUNET_OK != expect_data_fixed (vec,
807 "cs_bs_beta_0",
808 &bs[0].beta,
809 sizeof (bs[0].beta)))
810 {
811 GNUNET_break (0);
812 return GNUNET_SYSERR;
813 }
814 if (GNUNET_OK !=
815 expect_data_fixed (vec,
816 "cs_bs_beta_1",
817 &bs[1].beta,
818 sizeof (bs[1].beta)))
819 {
820 GNUNET_break (0);
821 return GNUNET_SYSERR;
822 }
823 if (GNUNET_OK !=
824 expect_data_fixed (vec,
825 "cs_r_pub_blind_0",
826 &r_pub_blind.r_pub[0],
827 sizeof (r_pub_blind.r_pub[0])))
828 {
829 GNUNET_break (0);
830 return GNUNET_SYSERR;
831 }
832 if (GNUNET_OK !=
833 expect_data_fixed (vec,
834 "cs_r_pub_blind_1",
835 &r_pub_blind.r_pub[1],
836 sizeof (r_pub_blind.r_pub[1])))
837 {
838 GNUNET_break (0);
839 return GNUNET_SYSERR;
840 }
841 if (GNUNET_OK !=
842 expect_data_fixed (vec,
843 "cs_c_0",
844 &c[0],
845 sizeof (c[0])))
846 {
847 GNUNET_break (0);
848 return GNUNET_SYSERR;
849 }
850 if (GNUNET_OK != expect_data_fixed (vec,
851 "cs_c_1",
852 &c[1],
853 sizeof (c[1])))
854 {
855 GNUNET_break (0);
856 return GNUNET_SYSERR;
857 }
858 if (GNUNET_OK != expect_data_fixed (vec,
859 "cs_blind_s",
860 &blinded_s,
861 sizeof (blinded_s)))
862 {
863 GNUNET_break (0);
864 return GNUNET_SYSERR;
865 }
866 if (GNUNET_OK != expect_data_fixed (vec,
867 "cs_b",
868 &b,
869 sizeof (b)))
870 {
871 GNUNET_break (0);
872 return GNUNET_SYSERR;
873 }
874 if (GNUNET_OK != expect_data_fixed (vec,
875 "cs_sig_s",
876 &signature_scalar,
877 sizeof (signature_scalar)))
878 {
879 GNUNET_break (0);
880 return GNUNET_SYSERR;
881 }
882 sig.s_scalar = signature_scalar;
883 if (GNUNET_OK != expect_data_fixed (vec,
884 "cs_sig_R",
885 &sig.r_point,
886 sizeof (sig.r_point)))
887 {
888 GNUNET_break (0);
889 return GNUNET_SYSERR;
890 }
891
892 if ((b != 1) && (b != 0))
893 {
894 GNUNET_break (0);
895 return GNUNET_SYSERR;
896 }
897
898 struct GNUNET_CRYPTO_CsRSecret r_priv_comp[2];
899 struct GNUNET_CRYPTO_CsRPublic r_pub_comp[2];
900 struct GNUNET_CRYPTO_CsBlindingSecret bs_comp[2];
901 struct GNUNET_CRYPTO_CsC c_comp[2];
902 struct GNUNET_CRYPTO_CSPublicRPairP r_pub_blind_comp;
903 struct GNUNET_CRYPTO_CsBlindSignature blinded_s_comp;
904 struct GNUNET_CRYPTO_CsS signature_scalar_comp;
905 struct GNUNET_CRYPTO_CsSignature sig_comp;
906
907 GNUNET_CRYPTO_cs_r_derive (&snonce,
908 "rw",
909 &priv,
910 r_priv_comp);
911 GNUNET_CRYPTO_cs_r_get_public (&r_priv_comp[0],
912 &r_pub_comp[0]);
913 GNUNET_CRYPTO_cs_r_get_public (&r_priv_comp[1],
914 &r_pub_comp[1]);
915 GNUNET_assert (0 == memcmp (&r_priv_comp,
916 &r_priv,
917 sizeof(struct GNUNET_CRYPTO_CsRSecret) * 2));
918 GNUNET_assert (0 == memcmp (&r_pub_comp,
919 &r_pub,
920 sizeof(struct GNUNET_CRYPTO_CsRPublic) * 2));
921
922 GNUNET_CRYPTO_cs_blinding_secrets_derive (&bnonce,
923 bs_comp);
924 GNUNET_assert (0 ==
925 memcmp (&bs_comp,
926 &bs,
927 sizeof(struct GNUNET_CRYPTO_CsBlindingSecret)
928 * 2));
929 GNUNET_CRYPTO_cs_calc_blinded_c (bs_comp,
930 r_pub_comp,
931 &pub,
932 &message_hash,
933 sizeof(message_hash),
934 c_comp,
935 &r_pub_blind_comp);
936 GNUNET_assert (0 ==
937 memcmp (&c_comp,
938 &c,
939 sizeof(struct GNUNET_CRYPTO_CsC) * 2));
940 GNUNET_assert (0 ==
941 GNUNET_memcmp (&r_pub_blind_comp,
942 &r_pub_blind));
943 {
944 struct GNUNET_CRYPTO_CsBlindedMessage bm = {
945 .c[0] = c_comp[0],
946 .c[1] = c_comp[1],
947 .nonce = snonce
948 };
949
950 GNUNET_CRYPTO_cs_sign_derive (&priv,
951 r_priv_comp,
952 &bm,
953 &blinded_s_comp);
954 }
955 GNUNET_assert (0 ==
956 GNUNET_memcmp (&blinded_s_comp.s_scalar,
957 &blinded_s));
958 GNUNET_assert (b == blinded_s_comp.b);
959 GNUNET_CRYPTO_cs_unblind (&blinded_s_comp.s_scalar,
960 &bs_comp[b],
961 &signature_scalar_comp);
962 GNUNET_assert (0 ==
963 GNUNET_memcmp (&signature_scalar_comp,
964 &signature_scalar));
965 sig_comp.r_point = r_pub_blind_comp.r_pub[b];
966 sig_comp.s_scalar = signature_scalar_comp;
967 GNUNET_assert (0 == memcmp (&sig_comp,
968 &sig,
969 sizeof(sig_comp)));
970 if (GNUNET_OK !=
971 GNUNET_CRYPTO_cs_verify (&sig_comp,
972 &pub,
973 &message_hash,
974 sizeof(message_hash)))
975 {
976 GNUNET_break (0);
977 return GNUNET_SYSERR;
978 }
979 }
980 else
981 {
982 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
983 "unsupported operation '%s'\n", operation);
984 }
985
986 return GNUNET_OK;
987}
988
989
990/**
991 * Check test vectors from stdin.
992 *
993 * @returns global exit code
994 */
995static int
996check_vectors ()
997{
998 json_error_t err;
999 json_t *vecfile = json_loadf (stdin, 0, &err);
1000 const char *encoding;
1001 json_t *vectors;
1002
1003 if (NULL == vecfile)
1004 {
1005 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n");
1006 return 1;
1007 }
1008 encoding = json_string_value (json_object_get (vecfile,
1009 "encoding"));
1010 if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) )
1011 {
1012 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n");
1013 json_decref (vecfile);
1014 return 1;
1015 }
1016 vectors = json_object_get (vecfile, "vectors");
1017 if (! json_is_array (vectors))
1018 {
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n");
1020 json_decref (vecfile);
1021 return 1;
1022 }
1023 {
1024 /* array is a JSON array */
1025 size_t index;
1026 json_t *value;
1027 enum GNUNET_GenericReturnValue ret = GNUNET_OK;
1028
1029 json_array_foreach (vectors, index, value) {
1030 const char *op = json_string_value (json_object_get (value,
1031 "operation"));
1032
1033 if (NULL == op)
1034 {
1035 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1036 "missing operation\n");
1037 ret = GNUNET_SYSERR;
1038 break;
1039 }
1040 ret = checkvec (op, value);
1041 if (GNUNET_OK != ret)
1042 {
1043 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1044 "bad vector %u\n",
1045 (unsigned int) index);
1046 break;
1047 }
1048 }
1049 json_decref (vecfile);
1050 return (ret == GNUNET_OK) ? 0 : 1;
1051 }
1052}
1053
1054
1055/**
1056 * Output test vectors.
1057 *
1058 * @returns global exit code
1059 */
1060static int
1061output_vectors ()
1062{
1063 json_t *vecfile = json_object ();
1064 json_t *vecs = json_array ();
1065
1066 json_object_set_new (vecfile,
1067 "encoding",
1068 json_string ("base32crockford"));
1069 json_object_set_new (vecfile,
1070 "producer",
1071 json_string ("GNUnet " PACKAGE_VERSION " " VCS_VERSION));
1072 json_object_set_new (vecfile,
1073 "vectors",
1074 vecs);
1075
1076 {
1077 json_t *vec = vec_for (vecs, "hash");
1078 struct GNUNET_HashCode hc;
1079 char *str = "Hello, GNUnet";
1080
1081 GNUNET_CRYPTO_hash (str, strlen (str), &hc);
1082
1083 d2j (vec, "input", str, strlen (str));
1084 d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode));
1085 }
1086 {
1087 json_t *vec = vec_for (vecs, "ecc_ecdh");
1088 struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
1089 struct GNUNET_CRYPTO_EcdhePublicKey pub1;
1090 struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
1091 struct GNUNET_HashCode skm;
1092
1093 GNUNET_CRYPTO_ecdhe_key_create (&priv1);
1094 GNUNET_CRYPTO_ecdhe_key_create (&priv2);
1095 GNUNET_CRYPTO_ecdhe_key_get_public (&priv1,
1096 &pub1);
1097 GNUNET_assert (GNUNET_OK ==
1098 GNUNET_CRYPTO_ecc_ecdh (&priv2,
1099 &pub1,
1100 &skm));
1101
1102 d2j (vec,
1103 "priv1",
1104 &priv1,
1105 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1106 d2j (vec,
1107 "pub1",
1108 &pub1,
1109 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1110 d2j (vec,
1111 "priv2",
1112 &priv2,
1113 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1114 d2j (vec,
1115 "skm",
1116 &skm,
1117 sizeof (struct GNUNET_HashCode));
1118 }
1119
1120 {
1121 json_t *vec = vec_for (vecs, "eddsa_key_derivation");
1122 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
1123 struct GNUNET_CRYPTO_EddsaPublicKey pub;
1124
1125 GNUNET_CRYPTO_eddsa_key_create (&priv);
1126 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
1127 &pub);
1128
1129 d2j (vec,
1130 "priv",
1131 &priv,
1132 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
1133 d2j (vec,
1134 "pub",
1135 &pub,
1136 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
1137 }
1138 {
1139 json_t *vec = vec_for (vecs, "eddsa_signing");
1140 struct GNUNET_CRYPTO_EddsaPrivateKey priv;
1141 struct GNUNET_CRYPTO_EddsaPublicKey pub;
1142 struct GNUNET_CRYPTO_EddsaSignature sig;
1143 struct TestSignatureDataPS data = { 0 };
1144
1145 GNUNET_CRYPTO_eddsa_key_create (&priv);
1146 GNUNET_CRYPTO_eddsa_key_get_public (&priv,
1147 &pub);
1148 data.purpose.size = htonl (sizeof (data));
1149 data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
1150 GNUNET_CRYPTO_eddsa_sign (&priv,
1151 &data,
1152 &sig);
1153 GNUNET_assert (GNUNET_OK ==
1154 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST,
1155 &data,
1156 &sig,
1157 &pub));
1158
1159 d2j (vec,
1160 "priv",
1161 &priv,
1162 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
1163 d2j (vec,
1164 "pub",
1165 &pub,
1166 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
1167 d2j (vec,
1168 "data",
1169 &data,
1170 sizeof (struct TestSignatureDataPS));
1171 d2j (vec,
1172 "sig",
1173 &sig,
1174 sizeof (struct GNUNET_CRYPTO_EddsaSignature));
1175 }
1176
1177 {
1178 json_t *vec = vec_for (vecs, "kdf");
1179 size_t out_len = 64;
1180 char out[out_len];
1181 char *ikm = "I'm the secret input key material";
1182 char *salt = "I'm very salty";
1183 char *ctx = "I'm a context chunk, also known as 'info' in the RFC";
1184
1185 GNUNET_assert (GNUNET_OK ==
1186 GNUNET_CRYPTO_kdf (&out,
1187 out_len,
1188 salt,
1189 strlen (salt),
1190 ikm,
1191 strlen (ikm),
1192 ctx,
1193 strlen (ctx),
1194 NULL));
1195
1196 d2j (vec,
1197 "salt",
1198 salt,
1199 strlen (salt));
1200 d2j (vec,
1201 "ikm",
1202 ikm,
1203 strlen (ikm));
1204 d2j (vec,
1205 "ctx",
1206 ctx,
1207 strlen (ctx));
1208 uint2j (vec,
1209 "out_len",
1210 (unsigned int) out_len);
1211 d2j (vec,
1212 "out",
1213 out,
1214 out_len);
1215 }
1216 {
1217 json_t *vec = vec_for (vecs, "eddsa_ecdh");
1218 struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe;
1219 struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe;
1220 struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa;
1221 struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa;
1222 struct GNUNET_HashCode key_material;
1223
1224 GNUNET_CRYPTO_ecdhe_key_create (&priv_ecdhe);
1225 GNUNET_CRYPTO_ecdhe_key_get_public (&priv_ecdhe, &pub_ecdhe);
1226 GNUNET_CRYPTO_eddsa_key_create (&priv_eddsa);
1227 GNUNET_CRYPTO_eddsa_key_get_public (&priv_eddsa, &pub_eddsa);
1228 GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material);
1229
1230 d2j (vec, "priv_ecdhe",
1231 &priv_ecdhe,
1232 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1233 d2j (vec, "pub_ecdhe",
1234 &pub_ecdhe,
1235 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1236 d2j (vec, "priv_eddsa",
1237 &priv_eddsa,
1238 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
1239 d2j (vec, "pub_eddsa",
1240 &pub_eddsa,
1241 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
1242 d2j (vec, "key_material",
1243 &key_material,
1244 sizeof (struct GNUNET_HashCode));
1245 }
1246
1247 {
1248 json_t *vec = vec_for (vecs, "edx25519_derive");
1249 struct GNUNET_CRYPTO_Edx25519PrivateKey priv1_edx;
1250 struct GNUNET_CRYPTO_Edx25519PublicKey pub1_edx;
1251 struct GNUNET_CRYPTO_Edx25519PrivateKey priv2_edx;
1252 struct GNUNET_CRYPTO_Edx25519PublicKey pub2_edx;
1253 struct GNUNET_HashCode seed;
1254
1255 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1256 &seed,
1257 sizeof (struct GNUNET_HashCode));
1258 GNUNET_CRYPTO_edx25519_key_create (&priv1_edx);
1259 GNUNET_CRYPTO_edx25519_key_get_public (&priv1_edx, &pub1_edx);
1260 GNUNET_CRYPTO_edx25519_private_key_derive (&priv1_edx,
1261 &seed,
1262 sizeof (seed),
1263 &priv2_edx);
1264 GNUNET_CRYPTO_edx25519_public_key_derive (&pub1_edx,
1265 &seed,
1266 sizeof (seed),
1267 &pub2_edx);
1268
1269 d2j (vec, "priv1_edx",
1270 &priv1_edx,
1271 sizeof (struct GNUNET_CRYPTO_Edx25519PrivateKey));
1272 d2j (vec, "pub1_edx",
1273 &pub1_edx,
1274 sizeof (struct GNUNET_CRYPTO_Edx25519PublicKey));
1275 d2j (vec, "seed",
1276 &seed,
1277 sizeof (struct GNUNET_HashCode));
1278 d2j (vec, "priv2_edx",
1279 &priv2_edx,
1280 sizeof (struct GNUNET_CRYPTO_Edx25519PrivateKey));
1281 d2j (vec, "pub2_edx",
1282 &pub2_edx,
1283 sizeof (struct GNUNET_CRYPTO_Edx25519PublicKey));
1284 }
1285
1286 {
1287 json_t *vec = vec_for (vecs, "rsa_blind_signing");
1288
1289 struct GNUNET_CRYPTO_RsaPrivateKey *skey;
1290 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
1291 struct GNUNET_HashCode message_hash;
1292 struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
1293 struct GNUNET_CRYPTO_RsaSignature *blinded_sig;
1294 struct GNUNET_CRYPTO_RsaSignature *sig;
1295 struct GNUNET_CRYPTO_RsaBlindedMessage bm;
1296 void *public_enc_data;
1297 size_t public_enc_len;
1298 void *secret_enc_data;
1299 size_t secret_enc_len;
1300 void *blinded_sig_enc_data;
1301 size_t blinded_sig_enc_length;
1302 void *sig_enc_data;
1303 size_t sig_enc_length;
1304
1305 skey = GNUNET_CRYPTO_rsa_private_key_create (2048);
1306 pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey);
1307 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1308 &message_hash,
1309 sizeof (struct GNUNET_HashCode));
1310 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1311 &bks,
1312 sizeof (struct
1313 GNUNET_CRYPTO_RsaBlindingKeySecret));
1314 GNUNET_assert (GNUNET_YES ==
1315 GNUNET_CRYPTO_rsa_blind (&message_hash,
1316 sizeof (message_hash),
1317 &bks,
1318 pkey,
1319 &bm));
1320 blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey,
1321 &bm);
1322 sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig,
1323 &bks,
1324 pkey);
1325 GNUNET_assert (GNUNET_YES ==
1326 GNUNET_CRYPTO_rsa_verify (&message_hash,
1327 sizeof (message_hash),
1328 sig,
1329 pkey));
1330 public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
1331 &public_enc_data);
1332 secret_enc_len = GNUNET_CRYPTO_rsa_private_key_encode (skey,
1333 &secret_enc_data);
1334 blinded_sig_enc_length
1335 = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig,
1336 &blinded_sig_enc_data);
1337 sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig,
1338 &sig_enc_data);
1339 d2j (vec,
1340 "message_hash",
1341 &message_hash,
1342 sizeof (struct GNUNET_HashCode));
1343 d2j (vec,
1344 "rsa_public_key",
1345 public_enc_data,
1346 public_enc_len);
1347 d2j (vec,
1348 "rsa_private_key",
1349 secret_enc_data,
1350 secret_enc_len);
1351 d2j (vec,
1352 "blinding_key_secret",
1353 &bks,
1354 sizeof (struct GNUNET_CRYPTO_RsaBlindingKeySecret));
1355 d2j (vec,
1356 "blinded_message",
1357 bm.blinded_msg,
1358 bm.blinded_msg_size);
1359 d2j (vec,
1360 "blinded_sig",
1361 blinded_sig_enc_data,
1362 blinded_sig_enc_length);
1363 d2j (vec,
1364 "sig",
1365 sig_enc_data,
1366 sig_enc_length);
1367 GNUNET_CRYPTO_rsa_private_key_free (skey);
1368 GNUNET_CRYPTO_rsa_public_key_free (pkey);
1369 GNUNET_CRYPTO_rsa_signature_free (sig);
1370 GNUNET_CRYPTO_rsa_signature_free (blinded_sig);
1371 GNUNET_free (public_enc_data);
1372 GNUNET_CRYPTO_rsa_blinded_message_free (&bm);
1373 GNUNET_free (sig_enc_data);
1374 GNUNET_free (blinded_sig_enc_data);
1375 GNUNET_free (secret_enc_data);
1376 }
1377
1378 {
1379 json_t *vec = vec_for (vecs, "cs_blind_signing");
1380
1381 struct GNUNET_CRYPTO_CsPrivateKey priv;
1382 struct GNUNET_CRYPTO_CsPublicKey pub;
1383 struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
1384 struct GNUNET_CRYPTO_CsRSecret r_priv[2];
1385 struct GNUNET_CRYPTO_CsRPublic r_pub[2];
1386 struct GNUNET_CRYPTO_CSPublicRPairP r_pub_blind;
1387 struct GNUNET_CRYPTO_CsC c[2];
1388 struct GNUNET_CRYPTO_CsS signature_scalar;
1389 struct GNUNET_CRYPTO_CsBlindSignature blinded_s;
1390 struct GNUNET_CRYPTO_CsSignature sig;
1391 struct GNUNET_CRYPTO_CsSessionNonce snonce;
1392 struct GNUNET_CRYPTO_CsBlindingNonce bnonce;
1393 struct GNUNET_HashCode message_hash;
1394
1395 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1396 &message_hash,
1397 sizeof (struct GNUNET_HashCode));
1398
1399 GNUNET_CRYPTO_cs_private_key_generate (&priv);
1400 GNUNET_CRYPTO_cs_private_key_get_public (&priv,
1401 &pub);
1402 GNUNET_assert (GNUNET_YES ==
1403 GNUNET_CRYPTO_hkdf (&snonce,
1404 sizeof(snonce),
1405 GCRY_MD_SHA512,
1406 GCRY_MD_SHA256,
1407 "nonce",
1408 strlen ("nonce"),
1409 "nonce_secret",
1410 strlen ("nonce_secret"),
1411 NULL,
1412 0));
1413 /* NOTE: historically, we made the bad choice of
1414 making both nonces the same. Maybe barely OK
1415 for the TGV, not good for production! */
1416 memcpy (&bnonce,
1417 &snonce,
1418 sizeof (snonce));
1419 GNUNET_CRYPTO_cs_r_derive (&snonce,
1420 "rw",
1421 &priv,
1422 r_priv);
1423 GNUNET_CRYPTO_cs_r_get_public (&r_priv[0],
1424 &r_pub[0]);
1425 GNUNET_CRYPTO_cs_r_get_public (&r_priv[1],
1426 &r_pub[1]);
1427 GNUNET_CRYPTO_cs_blinding_secrets_derive (&bnonce,
1428 bs);
1429 GNUNET_CRYPTO_cs_calc_blinded_c (bs,
1430 r_pub,
1431 &pub,
1432 &message_hash,
1433 sizeof(message_hash),
1434 c,
1435 &r_pub_blind);
1436 {
1437 struct GNUNET_CRYPTO_CsBlindedMessage bm = {
1438 .c[0] = c[0],
1439 .c[1] = c[1],
1440 .nonce = snonce
1441 };
1442
1443 GNUNET_CRYPTO_cs_sign_derive (&priv,
1444 r_priv,
1445 &bm,
1446 &blinded_s);
1447 }
1448 GNUNET_CRYPTO_cs_unblind (&blinded_s.s_scalar,
1449 &bs[blinded_s.b],
1450 &signature_scalar);
1451 sig.r_point = r_pub_blind.r_pub[blinded_s.b];
1452 sig.s_scalar = signature_scalar;
1453 if (GNUNET_OK !=
1454 GNUNET_CRYPTO_cs_verify (&sig,
1455 &pub,
1456 &message_hash,
1457 sizeof(message_hash)))
1458 {
1459 GNUNET_break (0);
1460 return GNUNET_SYSERR;
1461 }
1462 d2j (vec,
1463 "message_hash",
1464 &message_hash,
1465 sizeof (struct GNUNET_HashCode));
1466 d2j (vec,
1467 "cs_public_key",
1468 &pub,
1469 sizeof(pub));
1470 d2j (vec,
1471 "cs_private_key",
1472 &priv,
1473 sizeof(priv));
1474 d2j (vec,
1475 "cs_nonce",
1476 &snonce,
1477 sizeof(snonce));
1478 d2j (vec,
1479 "cs_r_priv_0",
1480 &r_priv[0],
1481 sizeof(r_priv[0]));
1482 d2j (vec,
1483 "cs_r_priv_1",
1484 &r_priv[1],
1485 sizeof(r_priv[1]));
1486 d2j (vec,
1487 "cs_r_pub_0",
1488 &r_pub[0],
1489 sizeof(r_pub[0]));
1490 d2j (vec,
1491 "cs_r_pub_1",
1492 &r_pub[1],
1493 sizeof(r_pub[1]));
1494 d2j (vec,
1495 "cs_bs_alpha_0",
1496 &bs[0].alpha,
1497 sizeof(bs[0].alpha));
1498 d2j (vec,
1499 "cs_bs_alpha_1",
1500 &bs[1].alpha,
1501 sizeof(bs[1].alpha));
1502 d2j (vec,
1503 "cs_bs_beta_0",
1504 &bs[0].beta,
1505 sizeof(bs[0].beta));
1506 d2j (vec,
1507 "cs_bs_beta_1",
1508 &bs[1].beta,
1509 sizeof(bs[1].beta));
1510 d2j (vec,
1511 "cs_r_pub_blind_0",
1512 &r_pub_blind.r_pub[0],
1513 sizeof(r_pub_blind.r_pub[0]));
1514 d2j (vec,
1515 "cs_r_pub_blind_1",
1516 &r_pub_blind.r_pub[1],
1517 sizeof(r_pub_blind.r_pub[1]));
1518 d2j (vec,
1519 "cs_c_0",
1520 &c[0],
1521 sizeof(c[0]));
1522 d2j (vec,
1523 "cs_c_1",
1524 &c[1],
1525 sizeof(c[1]));
1526 d2j (vec,
1527 "cs_blind_s",
1528 &blinded_s,
1529 sizeof(blinded_s));
1530 d2j (vec,
1531 "cs_b",
1532 &blinded_s.b,
1533 sizeof(blinded_s.b));
1534 d2j (vec,
1535 "cs_sig_s",
1536 &signature_scalar,
1537 sizeof(signature_scalar));
1538 d2j (vec,
1539 "cs_sig_R",
1540 &r_pub_blind.r_pub[blinded_s.b],
1541 sizeof(r_pub_blind.r_pub[blinded_s.b]));
1542 }
1543
1544 json_dumpf (vecfile, stdout, JSON_INDENT (2));
1545 json_decref (vecfile);
1546 printf ("\n");
1547
1548 return 0;
1549}
1550
1551
1552/**
1553 * Main function that will be run.
1554 *
1555 * @param cls closure
1556 * @param args remaining command-line arguments
1557 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1558 * @param cfg configuration
1559 */
1560static void
1561run (void *cls,
1562 char *const *args,
1563 const char *cfgfile,
1564 const struct GNUNET_CONFIGURATION_Handle *cfg)
1565{
1566 if (GNUNET_YES == verify_flag)
1567 global_ret = check_vectors ();
1568 else
1569 global_ret = output_vectors ();
1570}
1571
1572
1573/**
1574 * The main function of the test vector generation tool.
1575 *
1576 * @param argc number of arguments from the command line
1577 * @param argv command line arguments
1578 * @return 0 ok, 1 on error
1579 */
1580int
1581main (int argc,
1582 char *const *argv)
1583{
1584 const struct GNUNET_GETOPT_CommandLineOption options[] = {
1585 GNUNET_GETOPT_option_flag ('V',
1586 "verify",
1587 gettext_noop (
1588 "verify a test vector from stdin"),
1589 &verify_flag),
1590 GNUNET_GETOPT_OPTION_END
1591 };
1592
1593 GNUNET_assert (GNUNET_OK ==
1594 GNUNET_log_setup ("gnunet-crypto-tvg",
1595 "INFO",
1596 NULL));
1597 if (GNUNET_OK !=
1598 GNUNET_PROGRAM_run (argc, argv,
1599 "gnunet-crypto-tvg",
1600 "Generate test vectors for cryptographic operations",
1601 options,
1602 &run, NULL))
1603 return 1;
1604 return global_ret;
1605}
1606
1607
1608/* end of gnunet-crypto-tvg.c */
diff --git a/src/cli/util/gnunet-ecc.c b/src/cli/util/gnunet-ecc.c
new file mode 100644
index 000000000..812745085
--- /dev/null
+++ b/src/cli/util/gnunet-ecc.c
@@ -0,0 +1,510 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 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 util/gnunet-ecc.c
23 * @brief tool to manipulate EDDSA key files
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testing_lib.h"
30#include <gcrypt.h>
31
32/**
33 * Number of characters a Base32-encoded public key requires.
34 */
35#define KEY_STR_LEN sizeof(struct GNUNET_CRYPTO_EddsaPublicKey) * 8 / 5 + 1
36
37/**
38 * Flag for listing public key.
39 */
40static int list_keys;
41
42/**
43 * Flag for listing public key.
44 */
45static unsigned int list_keys_count;
46
47/**
48 * Flag for printing public key.
49 */
50static int print_public_key;
51
52/**
53 * Flag for printing private key.
54 */
55static int print_private_key;
56
57/**
58 * Flag for printing public key in hex.
59 */
60static int print_public_key_hex;
61
62/**
63 * Flag for printing the output of random example operations.
64 */
65static int print_examples_flag;
66
67/**
68 * Option set to create a bunch of keys at once.
69 */
70static unsigned int make_keys;
71
72
73/**
74 * Create a flat file with a large number of key pairs for testing.
75 *
76 * @param fn File name to store the keys.
77 * @param prefix Desired prefix for the public keys, NULL if any key is OK.
78 */
79static void
80create_keys (const char *fn, const char *prefix)
81{
82 FILE *f;
83 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
84 struct GNUNET_CRYPTO_EddsaPublicKey target_pub;
85 static char vanity[KEY_STR_LEN + 1];
86 size_t len;
87 size_t n;
88 size_t rest;
89 unsigned char mask;
90 unsigned target_byte;
91 char *s;
92
93 if (NULL == (f = fopen (fn, "w+")))
94 {
95 fprintf (stderr, _ ("Failed to open `%s': %s\n"), fn, strerror (errno));
96 return;
97 }
98 if (NULL != prefix)
99 {
100 len = GNUNET_strlcpy (vanity, prefix, sizeof(vanity));
101 n = len * 5 / 8;
102 rest = len * 5 % 8;
103
104 memset (&vanity[len], '0', KEY_STR_LEN - len);
105 vanity[KEY_STR_LEN] = '\0';
106 GNUNET_assert (GNUNET_OK ==
107 GNUNET_CRYPTO_eddsa_public_key_from_string (vanity,
108 KEY_STR_LEN,
109 &target_pub));
110 if (0 != rest)
111 {
112 /**
113 * Documentation by example:
114 * vanity = "A"
115 * len = 1
116 * n = 5/8 = 0 (bytes)
117 * rest = 5%8 = 5 (bits)
118 * mask = ~(2**(8 - 5) - 1) = ~(2**3 - 1) = ~(8 - 1) = ~b111 = b11111000
119 */mask = ~((int) pow (2, 8 - rest) - 1);
120 target_byte = ((unsigned char *) &target_pub)[n] & mask;
121 }
122 else
123 {
124 /* Just so old (debian) versions of GCC calm down with the warnings. */
125 mask = target_byte = 0;
126 }
127 s = GNUNET_CRYPTO_eddsa_public_key_to_string (&target_pub);
128 fprintf (stderr,
129 _ ("Generating %u keys like %s, please wait"),
130 make_keys,
131 s);
132 GNUNET_free (s);
133 fprintf (stderr, "\nattempt %s [%u, %X]\n", vanity, (unsigned int) n, mask);
134 }
135 else
136 {
137 fprintf (stderr, _ ("Generating %u keys, please wait"), make_keys);
138 /* Just so old (debian) versions of GCC calm down with the warnings. */
139 n = rest = target_byte = mask = 0;
140 }
141
142 while (0 < make_keys--)
143 {
144 fprintf (stderr, ".");
145 GNUNET_CRYPTO_eddsa_key_create (&pk);
146 if (NULL != prefix)
147 {
148 struct GNUNET_CRYPTO_EddsaPublicKey newkey;
149
150 GNUNET_CRYPTO_eddsa_key_get_public (&pk,
151 &newkey);
152 if (0 != memcmp (&target_pub,
153 &newkey,
154 n))
155 {
156 make_keys++;
157 continue;
158 }
159 if (0 != rest)
160 {
161 unsigned char new_byte;
162
163 new_byte = ((unsigned char *) &newkey)[n] & mask;
164 if (target_byte != new_byte)
165 {
166 make_keys++;
167 continue;
168 }
169 }
170 }
171 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
172 fwrite (&pk,
173 1,
174 GNUNET_TESTING_HOSTKEYFILESIZE,
175 f))
176 {
177 fprintf (stderr,
178 _ ("\nFailed to write to `%s': %s\n"),
179 fn,
180 strerror (errno));
181 break;
182 }
183 }
184 if (UINT_MAX == make_keys)
185 fprintf (stderr, _ ("\nFinished!\n"));
186 else
187 fprintf (stderr, _ ("\nError, %u keys not generated\n"), make_keys);
188 fclose (f);
189}
190
191
192static void
193print_hex (const char *msg, const void *buf, size_t size)
194{
195 printf ("%s: ", msg);
196 for (size_t i = 0; i < size; i++)
197 {
198 printf ("%02hhx", ((const uint8_t *) buf)[i]);
199 }
200 printf ("\n");
201}
202
203
204static void
205print_examples_ecdh (void)
206{
207 struct GNUNET_CRYPTO_EcdhePrivateKey dh_priv1;
208 struct GNUNET_CRYPTO_EcdhePublicKey dh_pub1;
209 struct GNUNET_CRYPTO_EcdhePrivateKey dh_priv2;
210 struct GNUNET_CRYPTO_EcdhePublicKey dh_pub2;
211 struct GNUNET_HashCode hash;
212 char buf[128];
213
214 GNUNET_CRYPTO_ecdhe_key_create (&dh_priv1);
215 GNUNET_CRYPTO_ecdhe_key_create (&dh_priv2);
216 GNUNET_CRYPTO_ecdhe_key_get_public (&dh_priv1,
217 &dh_pub1);
218 GNUNET_CRYPTO_ecdhe_key_get_public (&dh_priv2,
219 &dh_pub2);
220
221 GNUNET_assert (NULL !=
222 GNUNET_STRINGS_data_to_string (&dh_priv1,
223 sizeof (dh_priv1),
224 buf,
225 sizeof (buf)));
226 printf ("ECDHE key 1:\n");
227 printf ("private: %s\n",
228 buf);
229 print_hex ("private(hex)",
230 &dh_priv1, sizeof (dh_priv1));
231 GNUNET_assert (NULL !=
232 GNUNET_STRINGS_data_to_string (&dh_pub1,
233 sizeof (dh_pub1),
234 buf,
235 sizeof (buf)));
236 printf ("public: %s\n",
237 buf);
238 print_hex ("public(hex)",
239 &dh_pub1,
240 sizeof (dh_pub1));
241
242 GNUNET_assert (NULL !=
243 GNUNET_STRINGS_data_to_string (&dh_priv2,
244 sizeof (dh_priv2),
245 buf,
246 sizeof (buf)));
247 printf ("ECDHE key 2:\n");
248 printf ("private: %s\n", buf);
249 print_hex ("private(hex)",
250 &dh_priv2,
251 sizeof (dh_priv2));
252 GNUNET_assert (NULL !=
253 GNUNET_STRINGS_data_to_string (&dh_pub2,
254 sizeof (dh_pub2),
255 buf,
256 sizeof (buf)));
257 printf ("public: %s\n", buf);
258 print_hex ("public(hex)",
259 &dh_pub2,
260 sizeof (dh_pub2));
261
262 GNUNET_assert (GNUNET_OK ==
263 GNUNET_CRYPTO_ecc_ecdh (&dh_priv1,
264 &dh_pub2,
265 &hash));
266 GNUNET_assert (NULL !=
267 GNUNET_STRINGS_data_to_string (&hash,
268 sizeof (hash),
269 buf,
270 sizeof (buf)));
271 printf ("ECDH shared secret: %s\n",
272 buf);
273
274}
275
276
277/**
278 * Print some random example operations to stdout.
279 */
280static void
281print_examples (void)
282{
283 print_examples_ecdh ();
284 // print_examples_ecdsa ();
285 // print_examples_eddsa ();
286}
287
288
289static void
290print_key (const char *filename)
291{
292 struct GNUNET_DISK_FileHandle *fd;
293 struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
294 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
295 char *hostkeys_data;
296 char *hostkey_str;
297 uint64_t fs;
298 unsigned int total_hostkeys;
299 unsigned int c;
300 ssize_t sret;
301
302 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
303 {
304 fprintf (stderr, _ ("Hostkeys file `%s' not found\n"), filename);
305 return;
306 }
307
308 /* Check hostkey file size, read entire thing into memory */
309 if (GNUNET_OK !=
310 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
311 fs = 0;
312 if (0 == fs)
313 {
314 fprintf (stderr, _ ("Hostkeys file `%s' is empty\n"), filename);
315 return; /* File is empty */
316 }
317 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
318 {
319 fprintf (stderr, _ ("Incorrect hostkey file format: %s\n"), filename);
320 return;
321 }
322 fd = GNUNET_DISK_file_open (filename,
323 GNUNET_DISK_OPEN_READ,
324 GNUNET_DISK_PERM_NONE);
325 if (NULL == fd)
326 {
327 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
328 return;
329 }
330 hostkeys_data = GNUNET_malloc (fs);
331 sret = GNUNET_DISK_file_read (fd, hostkeys_data, fs);
332 if ((sret < 0) || (fs != (size_t) sret))
333 {
334 fprintf (stderr, _ ("Could not read hostkey file: %s\n"), filename);
335 GNUNET_free (hostkeys_data);
336 GNUNET_DISK_file_close (fd);
337 return;
338 }
339 GNUNET_DISK_file_close (fd);
340
341 if (NULL == hostkeys_data)
342 return;
343 total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
344 for (c = 0; (c < total_hostkeys) && (c < list_keys_count); c++)
345 {
346 GNUNET_memcpy (&private_key,
347 hostkeys_data + (c * GNUNET_TESTING_HOSTKEYFILESIZE),
348 GNUNET_TESTING_HOSTKEYFILESIZE);
349 GNUNET_CRYPTO_eddsa_key_get_public (&private_key, &public_key);
350 hostkey_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&public_key);
351 if (NULL != hostkey_str)
352 {
353 fprintf (stderr, "%4u: %s\n", c, hostkey_str);
354 GNUNET_free (hostkey_str);
355 }
356 else
357 fprintf (stderr, "%4u: %s\n", c, "invalid");
358 }
359 GNUNET_free (hostkeys_data);
360}
361
362
363/**
364 * Main function that will be run by the scheduler.
365 *
366 * @param cls closure, NULL
367 * @param args remaining command-line arguments
368 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
369 * @param cfg configuration
370 */
371static void
372run (void *cls,
373 char *const *args,
374 const char *cfgfile,
375 const struct GNUNET_CONFIGURATION_Handle *cfg)
376{
377 (void) cls;
378 (void) cfgfile;
379 (void) cfg;
380
381 if (print_examples_flag)
382 {
383 print_examples ();
384 return;
385 }
386 if (NULL == args[0])
387 {
388 fprintf (stderr, "%s", _ ("No hostkey file specified on command line\n"));
389 return;
390 }
391 if (list_keys)
392 {
393 print_key (args[0]);
394 return;
395 }
396 if (make_keys > 0)
397 {
398 create_keys (args[0], args[1]);
399 return;
400 }
401 if (print_public_key || print_public_key_hex || print_private_key)
402 {
403 char *str;
404 struct GNUNET_DISK_FileHandle *keyfile;
405 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
406 struct GNUNET_CRYPTO_EddsaPublicKey pub;
407
408 keyfile = GNUNET_DISK_file_open (args[0],
409 GNUNET_DISK_OPEN_READ,
410 GNUNET_DISK_PERM_NONE);
411 if (NULL == keyfile)
412 return;
413 while (sizeof(pk) == GNUNET_DISK_file_read (keyfile, &pk, sizeof(pk)))
414 {
415 GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub);
416 if (print_public_key_hex)
417 {
418 print_hex ("HEX:", &pub, sizeof(pub));
419 }
420 else if (print_public_key)
421 {
422 str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
423 fprintf (stdout, "%s\n", str);
424 GNUNET_free (str);
425 }
426 else if (print_private_key)
427 {
428 str = GNUNET_CRYPTO_eddsa_private_key_to_string (&pk);
429 fprintf (stdout, "%s\n", str);
430 GNUNET_free (str);
431 }
432 }
433 GNUNET_DISK_file_close (keyfile);
434 }
435}
436
437
438/**
439 * Program to manipulate ECC key files.
440 *
441 * @param argc number of arguments from the command line
442 * @param argv command line arguments
443 * @return 0 ok, 1 on error
444 */
445int
446main (int argc, char *const *argv)
447{
448 struct GNUNET_GETOPT_CommandLineOption options[] =
449 { GNUNET_GETOPT_option_flag ('i',
450 "iterate",
451 gettext_noop (
452 "list keys included in a file (for testing)"),
453 &list_keys),
454 GNUNET_GETOPT_option_uint (
455 'e',
456 "end=",
457 "COUNT",
458 gettext_noop ("number of keys to list included in a file (for testing)"),
459 &list_keys_count),
460 GNUNET_GETOPT_option_uint (
461 'g',
462 "generate-keys",
463 "COUNT",
464 gettext_noop ("create COUNT public-private key pairs (for testing)"),
465 &make_keys),
466 GNUNET_GETOPT_option_flag ('p',
467 "print-public-key",
468 gettext_noop (
469 "print the public key in ASCII format"),
470 &print_public_key),
471 GNUNET_GETOPT_option_flag ('P',
472 "print-private-key",
473 gettext_noop (
474 "print the private key in ASCII format"),
475 &print_private_key),
476 GNUNET_GETOPT_option_flag ('x',
477 "print-hex",
478 gettext_noop (
479 "print the public key in HEX format"),
480 &print_public_key_hex),
481 GNUNET_GETOPT_option_flag (
482 'E',
483 "examples",
484 gettext_noop (
485 "print examples of ECC operations (used for compatibility testing)"),
486 &print_examples_flag),
487 GNUNET_GETOPT_OPTION_END };
488 int ret;
489
490 list_keys_count = UINT32_MAX;
491 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
492 return 2;
493
494 ret = (GNUNET_OK ==
495 GNUNET_PROGRAM_run (argc,
496 argv,
497 "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
498 gettext_noop (
499 "Manipulate GNUnet private ECC key files"),
500 options,
501 &run,
502 NULL))
503 ? 0
504 : 1;
505 GNUNET_free_nz ((void *) argv);
506 return ret;
507}
508
509
510/* end of gnunet-ecc.c */
diff --git a/src/cli/util/gnunet-qr.c b/src/cli/util/gnunet-qr.c
new file mode 100644
index 000000000..d9b873c05
--- /dev/null
+++ b/src/cli/util/gnunet-qr.c
@@ -0,0 +1,597 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013-2019 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 util/gnunet-qr.c
22 * @author Hartmut Goebel (original implementation)
23 * @author Martin Schanzenbach (integrate gnunet-uri)
24 * @author Christian Grothoff (error handling)
25 */
26#include "platform.h"
27#include <stdio.h>
28#include <stdbool.h>
29#include <signal.h>
30#include <zbar.h>
31
32
33#include "gnunet_util_lib.h"
34
35#if HAVE_PNG
36#include <png.h>
37#endif
38
39/**
40 * Global exit code.
41 * Set to non-zero if an error occurs after the scheduler has started.
42 */
43static int exit_code = 0;
44
45/**
46 * Video device to capture from.
47 * Used by default if PNG support is disabled or no PNG file is specified.
48 * Defaults to /dev/video0.
49 */
50static char *device = NULL;
51
52#if HAVE_PNG
53/**
54 * Name of the file to read from.
55 * If the file is not a PNG-encoded image of a QR code, an error will be
56 * thrown.
57 */
58static char *pngfilename = NULL;
59#endif
60
61/**
62 * Requested verbosity.
63 */
64static unsigned int verbosity = 0;
65
66/**
67 * Child process handle.
68 */
69struct GNUNET_OS_Process *childproc = NULL;
70
71/**
72 * Child process handle for waiting.
73 */
74static struct GNUNET_ChildWaitHandle *waitchildproc = NULL;
75
76/**
77 * Macro to handle verbosity when printing messages.
78 */
79#define LOG(fmt, ...) \
80 do \
81 { \
82 if (0 < verbosity) \
83 { \
84 GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ##__VA_ARGS__); \
85 if (verbosity > 1) \
86 { \
87 fprintf (stdout, fmt, ##__VA_ARGS__); \
88 } \
89 } \
90 } \
91 while (0)
92
93/**
94 * Executed when program is terminating.
95 */
96static void
97shutdown_program (void *cls)
98{
99 if (NULL != waitchildproc)
100 {
101 GNUNET_wait_child_cancel (waitchildproc);
102 }
103 if (NULL != childproc)
104 {
105 /* A bit brutal, but this process is terminating so we're out of time */
106 GNUNET_OS_process_kill (childproc, SIGKILL);
107 }
108}
109
110/**
111 * Callback executed when the child process terminates.
112 *
113 * @param cls closure
114 * @param type status of the child process
115 * @param code the exit code of the child process
116 */
117static void
118wait_child (void *cls,
119 enum GNUNET_OS_ProcessStatusType type,
120 long unsigned int code)
121{
122 GNUNET_OS_process_destroy (childproc);
123 childproc = NULL;
124 waitchildproc = NULL;
125
126 char *uri = cls;
127
128 if (0 != exit_code)
129 {
130 fprintf (stdout, _("Failed to add URI %s\n"), uri);
131 }
132 else
133 {
134 fprintf (stdout, _("Added URI %s\n"), uri);
135 }
136
137 GNUNET_free (uri);
138
139 GNUNET_SCHEDULER_shutdown ();
140}
141
142/**
143 * Dispatch URIs to the appropriate GNUnet helper process.
144 *
145 * @param cls closure
146 * @param uri URI to dispatch
147 * @param cfgfile name of the configuration file in use
148 * @param cfg the configuration in use
149 */
150static void
151handle_uri (void *cls,
152 const char *uri,
153 const char *cfgfile,
154 const struct GNUNET_CONFIGURATION_Handle *cfg)
155{
156 const char *cursor = uri;
157
158 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
159 {
160 fprintf (stderr,
161 _("Invalid URI: does not start with `gnunet://'\n"));
162 exit_code = 1;
163 return;
164 }
165
166 cursor += strlen ("gnunet://");
167
168 const char *slash = strchr (cursor, '/');
169 if (NULL == slash)
170 {
171 fprintf (stderr, _("Invalid URI: fails to specify a subsystem\n"));
172 exit_code = 1;
173 return;
174 }
175
176 char *subsystem = GNUNET_strndup (cursor, slash - cursor);
177 char *program = NULL;
178
179 if (GNUNET_OK !=
180 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
181 {
182 fprintf (stderr, _("No known handler for subsystem `%s'\n"), subsystem);
183 GNUNET_free (subsystem);
184 exit_code = 1;
185 return;
186 }
187
188 GNUNET_free (subsystem);
189
190 char **childargv = NULL;
191 unsigned int childargc = 0;
192
193 for (const char *token=strtok (program, " ");
194 NULL!=token;
195 token=strtok(NULL, " "))
196 {
197 GNUNET_array_append (childargv, childargc, GNUNET_strdup (token));
198 }
199 GNUNET_array_append (childargv, childargc, GNUNET_strdup (uri));
200 GNUNET_array_append (childargv, childargc, NULL);
201
202 childproc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
203 NULL,
204 NULL,
205 NULL,
206 childargv[0],
207 childargv);
208 for (size_t i=0; i<childargc-1; ++i)
209 {
210 GNUNET_free (childargv[i]);
211 }
212
213 GNUNET_array_grow (childargv, childargc, 0);
214
215 if (NULL == childproc)
216 {
217 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
218 _("Unable to start child process `%s'\n"),
219 program);
220 GNUNET_free (program);
221 exit_code = 1;
222 return;
223 }
224
225 waitchildproc = GNUNET_wait_child (childproc, &wait_child, (void *)uri);
226}
227
228/**
229 * Obtain a QR code symbol from @a proc.
230 *
231 * @param proc the zbar processor to use
232 * @return NULL on error
233 */
234static const zbar_symbol_t *
235get_symbol (zbar_processor_t *proc)
236{
237 if (0 != zbar_processor_parse_config (proc, "enable"))
238 {
239 GNUNET_break (0);
240 return NULL;
241 }
242
243 int r = zbar_processor_init (proc, device, 1);
244 if (0 != r)
245 {
246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
247 _("Failed to open device: `%s': %d\n"),
248 device,
249 r);
250 return NULL;
251 }
252
253 r = zbar_processor_set_visible (proc, 1);
254 r += zbar_processor_set_active (proc, 1);
255 if (0 != r)
256 {
257 GNUNET_break (0);
258 return NULL;
259 }
260
261 LOG (_("Capturing...\n"));
262
263 int n = zbar_process_one (proc, -1);
264
265 zbar_processor_set_active (proc, 0);
266 zbar_processor_set_visible (proc, 0);
267
268 if (-1 == n)
269 {
270 LOG (_("No captured images\n"));
271 return NULL;
272 }
273
274 LOG(_("Got %d images\n"), n);
275
276 const zbar_symbol_set_t *symbols = zbar_processor_get_results (proc);
277 if (NULL == symbols)
278 {
279 GNUNET_break (0);
280 return NULL;
281 }
282
283 return zbar_symbol_set_first_symbol (symbols);
284}
285
286/**
287 * Run the zbar QR code parser.
288 *
289 * @return NULL on error
290 */
291static char *
292run_zbar (void)
293{
294 zbar_processor_t *proc = zbar_processor_create (1);
295 if (NULL == proc)
296 {
297 GNUNET_break (0);
298 return NULL;
299 }
300
301 if (NULL == device)
302 {
303 device = GNUNET_strdup ("/dev/video0");
304 }
305
306 const zbar_symbol_t *symbol = get_symbol (proc);
307 if (NULL == symbol)
308 {
309 zbar_processor_destroy (proc);
310 return NULL;
311 }
312
313 const char *data = zbar_symbol_get_data (symbol);
314 if (NULL == data)
315 {
316 GNUNET_break (0);
317 zbar_processor_destroy (proc);
318 return NULL;
319 }
320
321 LOG (_("Found %s: \"%s\"\n"),
322 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
323 data);
324
325 char *copy = GNUNET_strdup (data);
326
327 zbar_processor_destroy (proc);
328 GNUNET_free (device);
329
330 return copy;
331}
332
333#if HAVE_PNG
334/**
335 * Decode the PNG-encoded file to a raw byte buffer.
336 *
337 * @param width[out] where to store the image width
338 * @param height[out] where to store the image height
339 */
340static char *
341png_parse (uint32_t *width, uint32_t *height)
342{
343 if (NULL == width || NULL == height)
344 {
345 return NULL;
346 }
347
348 FILE *pngfile = fopen (pngfilename, "rb");
349 if (NULL == pngfile)
350 {
351 return NULL;
352 }
353
354 unsigned char header[8];
355 if (8 != fread (header, 1, 8, pngfile))
356 {
357 fclose (pngfile);
358 return NULL;
359 }
360
361 if (png_sig_cmp (header, 0, 8))
362 {
363 fclose (pngfile);
364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
365 _("%s is not a PNG file\n"),
366 pngfilename);
367 fprintf (stderr, _("%s is not a PNG file\n"), pngfilename);
368 return NULL;
369 }
370
371 /* libpng's default error handling might or might not conflict with GNUnet's
372 scheduler and event loop. Beware of strange interactions. */
373 png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
374 NULL,
375 NULL,
376 NULL);
377 if (NULL == png)
378 {
379 GNUNET_break (0);
380 fclose (pngfile);
381 return NULL;
382 }
383
384 png_infop pnginfo = png_create_info_struct (png);
385 if (NULL == pnginfo)
386 {
387 GNUNET_break (0);
388 png_destroy_read_struct (&png, NULL, NULL);
389 fclose (pngfile);
390 return NULL;
391 }
392
393 if (setjmp (png_jmpbuf (png)))
394 {
395 GNUNET_break (0);
396 png_destroy_read_struct (&png, &pnginfo, NULL);
397 fclose (pngfile);
398 return NULL;
399 }
400
401 png_init_io (png, pngfile);
402 png_set_sig_bytes (png, 8);
403
404 png_read_info (png, pnginfo);
405
406 png_byte pngcolor = png_get_color_type (png, pnginfo);
407 png_byte pngdepth = png_get_bit_depth (png, pnginfo);
408
409 /* Normalize picture --- based on a zbar example */
410 if (0 != (pngcolor & PNG_COLOR_TYPE_PALETTE))
411 {
412 png_set_palette_to_rgb (png);
413 }
414
415 if (pngcolor == PNG_COLOR_TYPE_GRAY && pngdepth < 8)
416 {
417 png_set_expand_gray_1_2_4_to_8 (png);
418 }
419
420 if (16 == pngdepth)
421 {
422 png_set_strip_16 (png);
423 }
424
425 if (0 != (pngcolor & PNG_COLOR_MASK_ALPHA))
426 {
427 png_set_strip_alpha (png);
428 }
429
430 if (0 != (pngcolor & PNG_COLOR_MASK_COLOR))
431 {
432 png_set_rgb_to_gray_fixed (png, 1, -1, -1);
433 }
434
435 png_uint_32 pngwidth = png_get_image_width (png, pnginfo);
436 png_uint_32 pngheight = png_get_image_height (png, pnginfo);
437
438 char *buffer = GNUNET_new_array (pngwidth * pngheight, char);
439 png_bytepp rows = GNUNET_new_array (pngheight, png_bytep);
440
441 for (png_uint_32 i=0; i<pngheight; ++i)
442 {
443 rows[i] = (unsigned char *)buffer + (pngwidth * i);
444 }
445
446 png_read_image (png, rows);
447
448 GNUNET_free (rows);
449 fclose (pngfile);
450
451 *width = pngwidth;
452 *height = pngheight;
453
454 return buffer;
455}
456
457/**
458 * Parse a PNG-encoded file for a QR code.
459 *
460 * @return NULL on error
461 */
462static char *
463run_png_reader (void)
464{
465 uint32_t width = 0;
466 uint32_t height = 0;
467 char *buffer = png_parse (&width, &height);
468 if (NULL == buffer)
469 {
470 return NULL;
471 }
472
473 zbar_image_scanner_t *scanner = zbar_image_scanner_create ();
474 zbar_image_scanner_set_config (scanner,0, ZBAR_CFG_ENABLE, 1);
475
476 zbar_image_t *zimage = zbar_image_create ();
477 zbar_image_set_format (zimage, zbar_fourcc ('Y', '8', '0', '0'));
478 zbar_image_set_size (zimage, width, height);
479 zbar_image_set_data (zimage, buffer, width * height, &zbar_image_free_data);
480
481 int n = zbar_scan_image (scanner, zimage);
482
483 if (-1 == n)
484 {
485 LOG (_("No captured images\n"));
486 return NULL;
487 }
488
489 LOG(_("Got %d images\n"), n);
490
491 const zbar_symbol_t *symbol = zbar_image_first_symbol (zimage);
492
493 const char *data = zbar_symbol_get_data (symbol);
494 if (NULL == data)
495 {
496 GNUNET_break (0);
497 zbar_image_destroy (zimage);
498 zbar_image_scanner_destroy (scanner);
499 return NULL;
500 }
501
502 LOG (_("Found %s: \"%s\"\n"),
503 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
504 data);
505
506 char *copy = GNUNET_strdup (data);
507
508 zbar_image_destroy (zimage);
509 zbar_image_scanner_destroy (scanner);
510
511 return copy;
512}
513#endif
514
515/**
516 * Main function executed by the scheduler.
517 *
518 * @param cls closure
519 * @param args remaining command line arguments
520 * @param cfgfile name of the configuration file being used
521 * @param cfg the used configuration
522 */
523static void
524run (void *cls,
525 char *const *args,
526 const char *cfgfile,
527 const struct GNUNET_CONFIGURATION_Handle *cfg)
528{
529 char *data = NULL;
530
531 GNUNET_SCHEDULER_add_shutdown (&shutdown_program, NULL);
532
533#if HAVE_PNG
534 if (NULL != pngfilename)
535 {
536 data = run_png_reader ();
537 }
538 else
539#endif
540 {
541 data = run_zbar ();
542 }
543
544 if (NULL == data)
545 {
546 LOG (_("No data found\n"));
547 exit_code = 1;
548 GNUNET_SCHEDULER_shutdown ();
549 return;
550 }
551
552 handle_uri (cls, data, cfgfile, cfg);
553
554 if (0 != exit_code)
555 {
556 fprintf (stdout, _("Failed to add URI %s\n"), data);
557 GNUNET_free (data);
558 GNUNET_SCHEDULER_shutdown ();
559 return;
560 }
561
562 LOG (_("Dispatching the URI\n"));
563}
564
565int
566main (int argc, char *const *argv)
567{
568 struct GNUNET_GETOPT_CommandLineOption options[] = {
569 GNUNET_GETOPT_option_string (
570 'd',
571 "device",
572 "DEVICE",
573 gettext_noop ("use the video device DEVICE (defaults to /dev/video0)"),
574 &device),
575#if HAVE_PNG
576 GNUNET_GETOPT_option_string (
577 'f',
578 "file",
579 "FILE",
580 gettext_noop ("read from the PNG-encoded file FILE"),
581 &pngfilename),
582#endif
583 GNUNET_GETOPT_option_verbose (&verbosity),
584 GNUNET_GETOPT_OPTION_END,
585 };
586
587 enum GNUNET_GenericReturnValue ret =
588 GNUNET_PROGRAM_run (argc,
589 argv,
590 "gnunet-qr",
591 gettext_noop ("Scan a QR code and import the URI read"),
592 options,
593 &run,
594 NULL);
595
596 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
597}
diff --git a/src/cli/util/gnunet-resolver.c b/src/cli/util/gnunet-resolver.c
new file mode 100644
index 000000000..a23aeb4aa
--- /dev/null
+++ b/src/cli/util/gnunet-resolver.c
@@ -0,0 +1,191 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010 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 util/gnunet-resolver.c
23 * @brief tool to test resolver
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_resolver_service.h"
30
31#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
32
33/**
34 * Flag for reverse lookup.
35 */
36static int reverse;
37
38
39/**
40 * Prints each hostname obtained from DNS.
41 *
42 * @param cls closure (unused)
43 * @param hostname one of the names for the host, NULL
44 * on the last call to the callback
45 */
46static void
47print_hostname (void *cls,
48 const char *hostname)
49{
50 (void) cls;
51 if (NULL == hostname)
52 return;
53 fprintf (stdout,
54 "%s\n",
55 hostname);
56}
57
58
59/**
60 * Callback function to display address.
61 *
62 * @param cls closure (unused)
63 * @param addr one of the addresses of the host, NULL for the last address
64 * @param addrlen length of the address
65 */
66static void
67print_sockaddr (void *cls,
68 const struct sockaddr *addr,
69 socklen_t addrlen)
70{
71 (void) cls;
72 if (NULL == addr)
73 return;
74 fprintf (stdout,
75 "%s\n",
76 GNUNET_a2s (addr,
77 addrlen));
78}
79
80
81/**
82 * Main function that will be run by the scheduler.
83 *
84 * @param cls closure
85 * @param args remaining command-line arguments
86 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
87 * @param cfg configuration
88 */
89static void
90run (void *cls,
91 char *const *args,
92 const char *cfgfile,
93 const struct GNUNET_CONFIGURATION_Handle *cfg)
94{
95 const struct sockaddr *sa;
96 socklen_t salen;
97 struct sockaddr_in v4;
98 struct sockaddr_in6 v6;
99
100 (void) cls;
101 (void) cfgfile;
102 (void) cfg;
103 if (NULL == args[0])
104 return;
105 if (! reverse)
106 {
107 GNUNET_RESOLVER_ip_get (args[0],
108 AF_UNSPEC,
109 GET_TIMEOUT,
110 &print_sockaddr,
111 NULL);
112 return;
113 }
114
115 sa = NULL;
116 memset (&v4, 0, sizeof(v4));
117 v4.sin_family = AF_INET;
118#if HAVE_SOCKADDR_IN_SIN_LEN
119 v4.sin_len = sizeof(v4);
120#endif
121 if (1 == inet_pton (AF_INET,
122 args[0],
123 &v4.sin_addr))
124 {
125 sa = (struct sockaddr *) &v4;
126 salen = sizeof(v4);
127 }
128 memset (&v6, 0, sizeof(v6));
129 v6.sin6_family = AF_INET6;
130#if HAVE_SOCKADDR_IN_SIN_LEN
131 v6.sin6_len = sizeof(v6);
132#endif
133 if (1 == inet_pton (AF_INET6,
134 args[0],
135 &v6.sin6_addr))
136 {
137 sa = (struct sockaddr *) &v6;
138 salen = sizeof(v6);
139 }
140 if (NULL == sa)
141 {
142 fprintf (stderr,
143 "`%s' is not a valid IP: %s\n",
144 args[0],
145 strerror (errno));
146 return;
147 }
148 GNUNET_RESOLVER_hostname_get (sa, salen,
149 GNUNET_YES,
150 GET_TIMEOUT,
151 &print_hostname,
152 NULL);
153}
154
155
156/**
157 * The main function to access GNUnet's DNS resolver.
158 *
159 * @param argc number of arguments from the command line
160 * @param argv command line arguments
161 * @return 0 ok, 1 on error
162 */
163int
164main (int argc, char *const *argv)
165{
166 struct GNUNET_GETOPT_CommandLineOption options[] = {
167 GNUNET_GETOPT_option_flag ('r',
168 "reverse",
169 gettext_noop ("perform a reverse lookup"),
170 &reverse),
171 GNUNET_GETOPT_OPTION_END
172 };
173 int ret;
174
175 if (GNUNET_OK !=
176 GNUNET_STRINGS_get_utf8_args (argc, argv,
177 &argc, &argv))
178 return 2;
179
180 ret = (GNUNET_OK ==
181 GNUNET_PROGRAM_run (argc, argv,
182 "gnunet-resolver [hostname]",
183 gettext_noop ("Use built-in GNUnet stub resolver"),
184 options,
185 &run, NULL)) ? 0 : 1;
186 GNUNET_free_nz ((void *) argv);
187 return ret;
188}
189
190
191/* end of gnunet-resolver.c */
diff --git a/src/cli/util/gnunet-scrypt.c b/src/cli/util/gnunet-scrypt.c
new file mode 100644
index 000000000..3d1b9c017
--- /dev/null
+++ b/src/cli/util/gnunet-scrypt.c
@@ -0,0 +1,325 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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 util/gnunet-scrypt.c
22 * @brief tool to manipulate SCRYPT proofs of work.
23 * @author Bart Polot
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include <gcrypt.h>
29
30
31/**
32 * Salt for PoW calcualations.
33 */
34static struct GNUNET_CRYPTO_PowSalt salt = { "gnunet-nse-proof" };
35
36
37/**
38 * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
39 */
40static unsigned long long nse_work_required;
41
42/**
43 * Interval between proof find runs.
44 */
45static struct GNUNET_TIME_Relative proof_find_delay;
46
47static struct GNUNET_CRYPTO_EddsaPublicKey pub;
48
49static uint64_t proof;
50
51static struct GNUNET_SCHEDULER_Task *proof_task;
52
53static const struct GNUNET_CONFIGURATION_Handle *cfg;
54
55static char *pkfn;
56
57static char *pwfn;
58
59
60/**
61 * Write our current proof to disk.
62 *
63 * @param cls closure
64 */
65static void
66shutdown_task (void *cls)
67{
68 (void) cls;
69 if (GNUNET_OK !=
70 GNUNET_DISK_fn_write (pwfn,
71 &proof,
72 sizeof(proof),
73 GNUNET_DISK_PERM_USER_READ
74 | GNUNET_DISK_PERM_USER_WRITE))
75 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
76 "write",
77 pwfn);
78}
79
80
81/**
82 * Find our proof of work.
83 *
84 * @param cls closure (unused)
85 */
86static void
87find_proof (void *cls)
88{
89#define ROUND_SIZE 10
90 uint64_t counter;
91 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
92 + sizeof(uint64_t)] GNUNET_ALIGN;
93 struct GNUNET_HashCode result;
94 unsigned int i;
95 struct GNUNET_TIME_Absolute timestamp;
96 struct GNUNET_TIME_Relative elapsed;
97
98 (void) cls;
99 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
100 "Got Proof of Work %llu\n",
101 (unsigned long long) proof);
102 proof_task = NULL;
103 GNUNET_memcpy (&buf[sizeof(uint64_t)],
104 &pub,
105 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
106 i = 0;
107 counter = proof;
108 timestamp = GNUNET_TIME_absolute_get ();
109 while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
110 {
111 GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
112 GNUNET_CRYPTO_pow_hash (&salt,
113 buf,
114 sizeof(buf),
115 &result);
116 if (nse_work_required <=
117 GNUNET_CRYPTO_hash_count_leading_zeros (&result))
118 {
119 proof = counter;
120 fprintf (stdout,
121 "Proof of work found: %llu!\n",
122 (unsigned long long) proof);
123 GNUNET_SCHEDULER_shutdown ();
124 return;
125 }
126 counter++;
127 i++;
128 }
129 elapsed = GNUNET_TIME_absolute_get_duration (timestamp);
130 elapsed = GNUNET_TIME_relative_divide (elapsed, ROUND_SIZE);
131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
132 "Current: %llu [%s/proof]\n",
133 (unsigned long long) counter,
134 GNUNET_STRINGS_relative_time_to_string (elapsed, 0));
135 if (proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
136 {
137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
138 "Testing proofs currently at %llu\n",
139 (unsigned long long) counter);
140 /* remember progress every 100 rounds */
141 proof = counter;
142 shutdown_task (NULL);
143 }
144 else
145 {
146 proof = counter;
147 }
148 proof_task =
149 GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
150 GNUNET_SCHEDULER_PRIORITY_IDLE,
151 &find_proof,
152 NULL);
153}
154
155
156/**
157 * Main function that will be run by the scheduler.
158 *
159 * @param cls closure
160 * @param args remaining command-line arguments
161 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
162 * @param cfg configuration
163 */
164static void
165run (void *cls,
166 char *const *args,
167 const char *cfgfile,
168 const struct GNUNET_CONFIGURATION_Handle *config)
169{
170 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
171 char *pids;
172
173 (void) cls;
174 (void) args;
175 (void) cfgfile;
176 cfg = config;
177 /* load proof of work */
178 if (NULL == pwfn)
179 {
180 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
181 "NSE",
182 "PROOFFILE",
183 &pwfn))
184 {
185 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
186 GNUNET_SCHEDULER_shutdown ();
187 return;
188 }
189 }
190 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Proof of Work file: %s\n", pwfn);
191 if ((GNUNET_YES != GNUNET_DISK_file_test (pwfn)) ||
192 (sizeof(proof) != GNUNET_DISK_fn_read (pwfn, &proof, sizeof(proof))))
193 proof = 0;
194
195 /* load private key */
196 if (NULL == pkfn)
197 {
198 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
199 "PEER",
200 "PRIVATE_KEY",
201 &pkfn))
202 {
203 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
204 "PEER",
205 "PRIVATE_KEY");
206 return;
207 }
208 }
209 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Private Key file: %s\n", pkfn);
210 if (GNUNET_SYSERR ==
211 GNUNET_CRYPTO_eddsa_key_from_file (pkfn,
212 GNUNET_YES,
213 &pk))
214 {
215 fprintf (stderr, _ ("Loading hostkey from `%s' failed.\n"), pkfn);
216 GNUNET_free (pkfn);
217 return;
218 }
219 GNUNET_free (pkfn);
220 GNUNET_CRYPTO_eddsa_key_get_public (&pk,
221 &pub);
222 pids = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
223 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer ID: %s\n", pids);
224 GNUNET_free (pids);
225
226 /* get target bit amount */
227 if (0 == nse_work_required)
228 {
229 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
230 "NSE",
231 "WORKBITS",
232 &nse_work_required))
233 {
234 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
235 GNUNET_SCHEDULER_shutdown ();
236 return;
237 }
238 if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
239 {
240 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
241 "NSE",
242 "WORKBITS",
243 _ ("Value is too large.\n"));
244 GNUNET_SCHEDULER_shutdown ();
245 return;
246 }
247 else if (0 == nse_work_required)
248 {
249 GNUNET_SCHEDULER_shutdown ();
250 return;
251 }
252 }
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bits: %llu\n", nse_work_required);
254
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256 "Delay between tries: %s\n",
257 GNUNET_STRINGS_relative_time_to_string (proof_find_delay, 1));
258 proof_task =
259 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
260 &find_proof,
261 NULL);
262 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
263}
264
265
266/**
267 * Program to manipulate ECC key files.
268 *
269 * @param argc number of arguments from the command line
270 * @param argv command line arguments
271 * @return 0 ok, 1 on error
272 */
273int
274main (int argc, char *const *argv)
275{
276 struct GNUNET_GETOPT_CommandLineOption options[] = {
277 GNUNET_GETOPT_option_ulong (
278 'b',
279 "bits",
280 "BITS",
281 gettext_noop ("number of bits to require for the proof of work"),
282 &nse_work_required),
283 GNUNET_GETOPT_option_filename (
284 'k',
285 "keyfile",
286 "FILE",
287 gettext_noop ("file with private key, otherwise default is used"),
288 &pkfn),
289 GNUNET_GETOPT_option_filename (
290 'o',
291 "outfile",
292 "FILE",
293 gettext_noop ("file with proof of work, otherwise default is used"),
294 &pwfn),
295 GNUNET_GETOPT_option_relative_time ('t',
296 "timeout",
297 "TIME",
298 gettext_noop (
299 "time to wait between calculations"),
300 &proof_find_delay),
301 GNUNET_GETOPT_OPTION_END
302 };
303 int ret;
304
305 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
306 return 2;
307
308 ret =
309 (GNUNET_OK ==
310 GNUNET_PROGRAM_run (argc,
311 argv,
312 "gnunet-scrypt [OPTIONS] prooffile",
313 gettext_noop ("Manipulate GNUnet proof of work files"),
314 options,
315 &run,
316 NULL))
317 ? 0
318 : 1;
319 GNUNET_free_nz ((void *) argv);
320 GNUNET_free (pwfn);
321 return ret;
322}
323
324
325/* end of gnunet-scrypt.c */
diff --git a/src/cli/util/gnunet-timeout.c b/src/cli/util/gnunet-timeout.c
new file mode 100644
index 000000000..1d3002c08
--- /dev/null
+++ b/src/cli/util/gnunet-timeout.c
@@ -0,0 +1,119 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010 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, or
8 (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 src/util/gnunet-timeout.c
23 * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period
24 * @author Matthias Wachs
25 */
26
27#include "platform.h"
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34
35static pid_t child;
36
37
38static void
39sigchld_handler (int val)
40{
41 int status = 0;
42 int ret = 0;
43
44 (void) val;
45 waitpid (child, &status, 0);
46 if (WIFEXITED (status) != 0)
47 {
48 ret = WEXITSTATUS (status);
49 _exit (ret); /* return same status code */
50 }
51 if (WIFSIGNALED (status) != 0)
52 {
53 ret = WTERMSIG (status);
54 kill (getpid (), ret); /* kill self with the same signal */
55 }
56 _exit (-1);
57}
58
59
60static void
61sigint_handler (int val)
62{
63 kill (0, val);
64 _exit (val);
65}
66
67
68int
69main (int argc, char *argv[])
70{
71 int timeout = 0;
72 pid_t gpid = 0;
73
74 if (argc < 3)
75 {
76 fprintf (stderr,
77 "arg 1: timeout in sec., arg 2: executable, arg<n> arguments\n");
78 exit (-1);
79 }
80
81 timeout = atoi (argv[1]);
82
83 if (timeout == 0)
84 timeout = 600;
85
86 /* with getpgid() it does not compile, but getpgrp is the BSD version and working */
87 gpid = getpgrp ();
88
89 signal (SIGCHLD, sigchld_handler);
90 signal (SIGABRT, sigint_handler);
91 signal (SIGFPE, sigint_handler);
92 signal (SIGILL, sigint_handler);
93 signal (SIGINT, sigint_handler);
94 signal (SIGSEGV, sigint_handler);
95 signal (SIGTERM, sigint_handler);
96
97 child = fork ();
98 if (child == 0)
99 {
100 /* int setpgrp(pid_t pid, pid_t pgid); is not working on this machine */
101 // setpgrp (0, pid_t gpid);
102 if (-1 != gpid)
103 setpgid (0, gpid);
104 execvp (argv[2], &argv[2]);
105 exit (-1);
106 }
107 if (child > 0)
108 {
109 sleep (timeout);
110 printf ("Child processes were killed after timeout of %u seconds\n",
111 timeout);
112 kill (0, SIGTERM);
113 exit (3);
114 }
115 exit (-1);
116}
117
118
119/* end of timeout_watchdog.c */
diff --git a/src/cli/util/gnunet-uri.c b/src/cli/util/gnunet-uri.c
new file mode 100644
index 000000000..128167cc5
--- /dev/null
+++ b/src/cli/util/gnunet-uri.c
@@ -0,0 +1,192 @@
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/**
22 * @file util/gnunet-uri.c
23 * @brief tool to dispatch URIs to the appropriate GNUnet helper process
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30/**
31 * Handler exit code
32 */
33static long unsigned int exit_code = 0;
34
35/**
36 * Helper process we started.
37 */
38static struct GNUNET_OS_Process *p;
39
40/**
41 * Pipe used to communicate shutdown via signal.
42 */
43static struct GNUNET_DISK_PipeHandle *sigpipe;
44
45
46/**
47 * Task triggered whenever we receive a SIGCHLD (child
48 * process died) or when user presses CTRL-C.
49 *
50 * @param cls closure, NULL
51 */
52static void
53maint_child_death (void *cls)
54{
55 enum GNUNET_OS_ProcessStatusType type;
56
57 (void) cls;
58 if ((GNUNET_OK != GNUNET_OS_process_status (p, &type, &exit_code)) ||
59 (type != GNUNET_OS_PROCESS_EXITED))
60 GNUNET_break (0 == GNUNET_OS_process_kill (p, GNUNET_TERM_SIG));
61 GNUNET_OS_process_destroy (p);
62}
63
64
65/**
66 * Main function that will be run by the scheduler.
67 *
68 * @param cls closure
69 * @param args remaining command-line arguments
70 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
71 * @param cfg configuration
72 */
73static void
74run (void *cls,
75 char *const *args,
76 const char *cfgfile,
77 const struct GNUNET_CONFIGURATION_Handle *cfg)
78{
79 const char *uri;
80 const char *slash;
81 char *subsystem;
82 char *program;
83 struct GNUNET_SCHEDULER_Task *rt;
84
85 (void) cls;
86 (void) cfgfile;
87 if (NULL == (uri = args[0]))
88 {
89 fprintf (stderr, _ ("No URI specified on command line\n"));
90 return;
91 }
92 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
93 {
94 fprintf (stderr,
95 _ ("Invalid URI: does not start with `%s'\n"),
96 "gnunet://");
97 return;
98 }
99 uri += strlen ("gnunet://");
100 if (NULL == (slash = strchr (uri, '/')))
101 {
102 fprintf (stderr, _ ("Invalid URI: fails to specify subsystem\n"));
103 return;
104 }
105 subsystem = GNUNET_strndup (uri, slash - uri);
106 if (GNUNET_OK !=
107 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
108 {
109 fprintf (stderr, _ ("No handler known for subsystem `%s'\n"), subsystem);
110 GNUNET_free (subsystem);
111 return;
112 }
113 GNUNET_free (subsystem);
114 rt = GNUNET_SCHEDULER_add_read_file (
115 GNUNET_TIME_UNIT_FOREVER_REL,
116 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
117 &maint_child_death,
118 NULL);
119 p = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_NONE,
120 NULL,
121 NULL,
122 NULL,
123 program,
124 program,
125 args[0],
126 NULL);
127 GNUNET_free (program);
128 if (NULL == p)
129 GNUNET_SCHEDULER_cancel (rt);
130}
131
132
133/**
134 * Signal handler called for SIGCHLD. Triggers the
135 * respective handler by writing to the trigger pipe.
136 */
137static void
138sighandler_child_death ()
139{
140 static char c;
141 int old_errno = errno; /* back-up errno */
142
143 GNUNET_break (
144 1 ==
145 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
146 GNUNET_DISK_PIPE_END_WRITE),
147 &c,
148 sizeof(c)));
149 errno = old_errno; /* restore errno */
150}
151
152
153/**
154 * The main function to handle gnunet://-URIs.
155 *
156 * @param argc number of arguments from the command line
157 * @param argv command line arguments
158 * @return 0 ok, 1 on error
159 */
160int
161main (int argc, char *const *argv)
162{
163 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
164 GNUNET_GETOPT_OPTION_END
165 };
166 struct GNUNET_SIGNAL_Context *shc_chld;
167 int ret;
168
169 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
170 return 2;
171 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
172 GNUNET_assert (sigpipe != NULL);
173 shc_chld =
174 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
175 ret = GNUNET_PROGRAM_run (argc,
176 argv,
177 "gnunet-uri URI",
178 gettext_noop (
179 "Perform default-actions for GNUnet URIs"),
180 options,
181 &run,
182 NULL);
183 GNUNET_SIGNAL_handler_uninstall (shc_chld);
184 shc_chld = NULL;
185 GNUNET_DISK_pipe_close (sigpipe);
186 sigpipe = NULL;
187 GNUNET_free_nz ((void *) argv);
188 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
189}
190
191
192/* end of gnunet-uri.c */
diff --git a/src/cli/util/meson.build b/src/cli/util/meson.build
new file mode 100644
index 000000000..ed9c3105c
--- /dev/null
+++ b/src/cli/util/meson.build
@@ -0,0 +1,62 @@
1executable ('gnunet-base32',
2 ['gnunet-base32.c'],
3 dependencies: [libgnunetutil_dep],
4 include_directories: [incdir, configuration_inc],
5 install: true,
6 install_dir: get_option('bindir'))
7executable ('gnunet-config',
8 ['gnunet-config.c'],
9 dependencies: [libgnunetutil_dep],
10 include_directories: [incdir, configuration_inc],
11 install: true,
12 install_dir: get_option('bindir'))
13executable ('gnunet-resolver',
14 ['gnunet-resolver.c'],
15 dependencies: [libgnunetutil_dep],
16 include_directories: [incdir, configuration_inc],
17 install: true,
18 install_dir: get_option('bindir'))
19executable ('gnunet-ecc',
20 ['gnunet-ecc.c'],
21 dependencies: [libgnunetutil_dep, gcrypt_dep, m_dep],
22 include_directories: [incdir, configuration_inc],
23 install: true,
24 install_dir: get_option('bindir'))
25executable ('gnunet-scrypt',
26 ['gnunet-scrypt.c'],
27 dependencies: [libgnunetutil_dep],
28 include_directories: [incdir, configuration_inc],
29 install: true,
30 install_dir: get_option('bindir'))
31executable ('gnunet-uri',
32 ['gnunet-uri.c'],
33 dependencies: [libgnunetutil_dep],
34 include_directories: [incdir, configuration_inc],
35 install: true,
36 install_dir: get_option('bindir'))
37if zbar_dep.found()
38 executable ('gnunet-qr',
39 ['gnunet-qr.c'],
40 dependencies: [zbar_dep, libgnunetutil_dep],
41 include_directories: [incdir, configuration_inc],
42 install: true,
43 install_dir: get_option('bindir'))
44endif
45executable ('gnunet-config-diff',
46 ['gnunet-config-diff.c'],
47 dependencies: [libgnunetutil_dep],
48 include_directories: [incdir, configuration_inc],
49 install: false)
50
51executable ('gnunet-timeout',
52 ['gnunet-timeout.c'],
53 dependencies: [libgnunetutil_dep],
54 include_directories: [incdir, configuration_inc],
55 install: true,
56 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
57executable ('gnunet-crypto-tvg',
58 ['gnunet-crypto-tvg.c'],
59 dependencies: [libgnunetutil_dep, json_dep],
60 include_directories: [incdir, configuration_inc],
61 install: false)
62
diff --git a/src/cli/util/test_crypto_vectors.sh b/src/cli/util/test_crypto_vectors.sh
new file mode 100755
index 000000000..40700a324
--- /dev/null
+++ b/src/cli/util/test_crypto_vectors.sh
@@ -0,0 +1,3 @@
1#!/usr/bin/env bash
2
3cat ./crypto-test-vectors.json | ./gnunet-crypto-tvg --verify
diff --git a/src/cli/vpn/.gitignore b/src/cli/vpn/.gitignore
new file mode 100644
index 000000000..dbd75eb25
--- /dev/null
+++ b/src/cli/vpn/.gitignore
@@ -0,0 +1 @@
gnunet-vpn
diff --git a/src/cli/vpn/Makefile.am b/src/cli/vpn/Makefile.am
new file mode 100644
index 000000000..0c7c459ef
--- /dev/null
+++ b/src/cli/vpn/Makefile.am
@@ -0,0 +1,22 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6endif
7
8pkgcfgdir= $(pkgdatadir)/config.d/
9
10libexecdir= $(pkglibdir)/libexec/
11
12plugindir = $(libdir)/gnunet
13
14bin_PROGRAMS = \
15 gnunet-vpn
16
17gnunet_vpn_SOURCES = \
18 gnunet-vpn.c
19gnunet_vpn_LDADD = \
20 $(top_builddir)/src/service/vpn/libgnunetvpn.la \
21 $(top_builddir)/src/lib/util/libgnunetutil.la \
22 $(GN_LIBINTL)
diff --git a/src/cli/vpn/gnunet-vpn.c b/src/cli/vpn/gnunet-vpn.c
new file mode 100644
index 000000000..a67e17016
--- /dev/null
+++ b/src/cli/vpn/gnunet-vpn.c
@@ -0,0 +1,364 @@
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/**
22 * @file src/vpn/gnunet-vpn.c
23 * @brief Tool to manually request VPN tunnels to be created
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_vpn_service.h"
30
31
32/**
33 * Handle to vpn service.
34 */
35static struct GNUNET_VPN_Handle *handle;
36
37/**
38 * Opaque redirection request handle.
39 */
40static struct GNUNET_VPN_RedirectionRequest *request;
41
42/**
43 * Option -p: destination peer identity for service
44 */
45static char *peer_id;
46
47/**
48 * Option -s: service name (hash to get service descriptor)
49 */
50static char *service_name;
51
52/**
53 * Option -i: target IP
54 */
55static char *target_ip;
56
57/**
58 * Option -4: IPv4 requested.
59 */
60static int ipv4;
61
62/**
63 * Option -6: IPv6 requested.
64 */
65static int ipv6;
66
67/**
68 * Option -t: TCP requested.
69 */
70static int tcp;
71
72/**
73 * Option -u: UDP requested.
74 */
75static int udp;
76
77/**
78 * Selected level of verbosity.
79 */
80static unsigned int verbosity;
81
82/**
83 * Global return value.
84 */
85static int ret;
86
87/**
88 * Option '-d': duration of the mapping
89 */
90static struct GNUNET_TIME_Relative duration = { 5 * 60 * 1000 };
91
92
93/**
94 * Shutdown.
95 */
96static void
97do_disconnect (void *cls)
98{
99 if (NULL != request)
100 {
101 GNUNET_VPN_cancel_request (request);
102 request = NULL;
103 }
104 if (NULL != handle)
105 {
106 GNUNET_VPN_disconnect (handle);
107 handle = NULL;
108 }
109 GNUNET_free (peer_id);
110 GNUNET_free (service_name);
111 GNUNET_free (target_ip);
112}
113
114
115/**
116 * Callback invoked from the VPN service once a redirection is
117 * available. Provides the IP address that can now be used to
118 * reach the requested destination.
119 *
120 * @param cls closure
121 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
122 * will match 'result_af' from the request
123 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
124 * that the VPN allocated for the redirection;
125 * traffic to this IP will now be redirected to the
126 * specified target peer; NULL on error
127 */
128static void
129allocation_cb (void *cls, int af, const void *address)
130{
131 char buf[INET6_ADDRSTRLEN];
132
133 request = NULL;
134 switch (af)
135 {
136 case AF_INET6:
137 case AF_INET:
138 fprintf (stdout, "%s\n", inet_ntop (af, address, buf, sizeof(buf)));
139 break;
140
141 case AF_UNSPEC:
142 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Error creating tunnel\n"));
143 ret = 1;
144 break;
145
146 default:
147 break;
148 }
149 GNUNET_SCHEDULER_shutdown ();
150}
151
152
153/**
154 * Main function that will be run by the scheduler.
155 *
156 * @param cls closure
157 * @param args remaining command-line arguments
158 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
159 * @param cfg configuration
160 */
161static void
162run (void *cls,
163 char *const *args,
164 const char *cfgfile,
165 const struct GNUNET_CONFIGURATION_Handle *cfg)
166{
167 int dst_af;
168 int req_af;
169 struct GNUNET_PeerIdentity peer;
170 struct GNUNET_HashCode sd;
171 const void *addr;
172 struct in_addr v4;
173 struct in6_addr v6;
174 uint8_t protocol;
175 struct GNUNET_TIME_Absolute etime;
176
177 etime = GNUNET_TIME_relative_to_absolute (duration);
178 GNUNET_SCHEDULER_add_shutdown (&do_disconnect, NULL);
179 handle = GNUNET_VPN_connect (cfg);
180 if (NULL == handle)
181 goto error;
182 req_af = AF_UNSPEC;
183 if (ipv4)
184 {
185 if (ipv6)
186 {
187 fprintf (stderr,
188 _ ("Option `%s' makes no sense with option `%s'.\n"),
189 "-4",
190 "-6");
191 goto error;
192 }
193 req_af = AF_INET;
194 }
195 if (ipv6)
196 req_af = AF_INET6;
197
198 if (NULL == target_ip)
199 {
200 if (NULL == service_name)
201 {
202 fprintf (stderr, _ ("Option `%s' or `%s' is required.\n"), "-i", "-s");
203 goto error;
204 }
205 if (NULL == peer_id)
206 {
207 fprintf (stderr,
208 _ ("Option `%s' is required when using option `%s'.\n"),
209 "-p",
210 "-s");
211 goto error;
212 }
213 if (! (tcp | udp))
214 {
215 fprintf (stderr,
216 _ ("Option `%s' or `%s' is required when using option `%s'.\n"),
217 "-t",
218 "-u",
219 "-s");
220 goto error;
221 }
222 if (tcp & udp)
223 {
224 fprintf (stderr,
225 _ ("Option `%s' makes no sense with option `%s'.\n"),
226 "-t",
227 "-u");
228 goto error;
229 }
230 if (tcp)
231 protocol = IPPROTO_TCP;
232 if (udp)
233 protocol = IPPROTO_UDP;
234 if (GNUNET_OK !=
235 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
236 strlen (peer_id),
237 &peer.public_key))
238 {
239 fprintf (stderr, _ ("`%s' is not a valid peer identifier.\n"), peer_id);
240 goto error;
241 }
242 GNUNET_TUN_service_name_to_hash (service_name, &sd);
243 request = GNUNET_VPN_redirect_to_peer (handle,
244 req_af,
245 protocol,
246 &peer,
247 &sd,
248 etime,
249 &allocation_cb,
250 NULL);
251 }
252 else
253 {
254 if (1 != inet_pton (AF_INET6, target_ip, &v6))
255 {
256 if (1 != inet_pton (AF_INET, target_ip, &v4))
257 {
258 fprintf (stderr, _ ("`%s' is not a valid IP address.\n"), target_ip);
259 goto error;
260 }
261 else
262 {
263 dst_af = AF_INET;
264 addr = &v4;
265 }
266 }
267 else
268 {
269 dst_af = AF_INET6;
270 addr = &v6;
271 }
272 request = GNUNET_VPN_redirect_to_ip (handle,
273 req_af,
274 dst_af,
275 addr,
276 etime,
277 &allocation_cb,
278 NULL);
279 }
280 return;
281
282error:
283 GNUNET_SCHEDULER_shutdown ();
284 ret = 1;
285}
286
287
288int
289main (int argc, char *const *argv)
290{
291 struct GNUNET_GETOPT_CommandLineOption options[] =
292 { GNUNET_GETOPT_option_flag ('4',
293 "ipv4",
294 gettext_noop (
295 "request that result should be an IPv4 address"),
296 &ipv4),
297
298 GNUNET_GETOPT_option_flag ('6',
299 "ipv6",
300 gettext_noop (
301 "request that result should be an IPv6 address"),
302 &ipv6),
303
304 GNUNET_GETOPT_option_relative_time (
305 'd',
306 "duration",
307 "TIME",
308 gettext_noop ("how long should the mapping be valid for new tunnels?"),
309 &duration),
310
311 GNUNET_GETOPT_option_string ('i',
312 "ip",
313 "IP",
314 gettext_noop (
315 "destination IP for the tunnel"),
316 &target_ip),
317
318 GNUNET_GETOPT_option_string (
319 'p',
320 "peer",
321 "PEERID",
322 gettext_noop ("peer offering the service we would like to access"),
323 &peer_id),
324
325 GNUNET_GETOPT_option_string ('s',
326 "service",
327 "NAME",
328 gettext_noop (
329 "name of the service we would like to access"),
330 &service_name),
331
332 GNUNET_GETOPT_option_flag ('t',
333 "tcp",
334 gettext_noop ("service is offered via TCP"),
335 &tcp),
336
337 GNUNET_GETOPT_option_flag ('u',
338 "udp",
339 gettext_noop ("service is offered via UDP"),
340 &udp),
341
342 GNUNET_GETOPT_option_verbose (&verbosity),
343
344 GNUNET_GETOPT_OPTION_END };
345
346 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
347 return 2;
348
349 ret =
350 (GNUNET_OK == GNUNET_PROGRAM_run (argc,
351 argv,
352 "gnunet-vpn",
353 gettext_noop ("Setup tunnels via VPN."),
354 options,
355 &run,
356 NULL))
357 ? ret
358 : 1;
359 GNUNET_free_nz ((void *) argv);
360 return ret;
361}
362
363
364/* end of gnunet-vpn.c */
diff --git a/src/cli/vpn/meson.build b/src/cli/vpn/meson.build
new file mode 100644
index 000000000..477551f1d
--- /dev/null
+++ b/src/cli/vpn/meson.build
@@ -0,0 +1,13 @@
1executable ('gnunet-vpn',
2 ['gnunet-vpn.c'],
3 dependencies: [libgnunetvpn_dep,
4 libgnunetutil_dep,
5 libgnunetstatistics_dep,
6 libgnunetregex_dep,
7 libgnunetcore_dep,
8 libgnunetcadet_dep,
9 libgnunetblock_dep],
10 include_directories: [incdir, configuration_inc, exitdir],
11 install: true,
12 install_dir: get_option('bindir'))
13