aboutsummaryrefslogtreecommitdiff
path: root/src/cli/gns/gnunet-gns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/gns/gnunet-gns.c')
-rw-r--r--src/cli/gns/gnunet-gns.c411
1 files changed, 411 insertions, 0 deletions
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 */