rps: store valid peer ids in file
[oweals/gnunet.git] / src / gns / gnunet-gns.c
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
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
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 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_identity_service.h>
29 #include <gnunet_gnsrecord_lib.h>
30 #include <gnunet_namestore_service.h>
31 #include <gnunet_gns_service.h>
32
33 /**
34  * Configuration we are using.
35  */
36 static const struct GNUNET_CONFIGURATION_Handle *cfg;
37
38 /**
39  * Handle to GNS service.
40  */
41 static struct GNUNET_GNS_Handle *gns;
42
43 /**
44  * Desired timeout for the lookup (default is no timeout).
45  */
46 static struct GNUNET_TIME_Relative timeout;
47
48 /**
49  * GNS name to lookup. (-u option)
50  */
51 static char *lookup_name;
52
53 /**
54  * record type to look up (-t option)
55  */
56 static char *lookup_type;
57
58 /**
59  * Identity of the zone to use for the lookup (-z option)
60  */
61 static char *zone_ego_name;
62
63 /**
64  * Public key of the zone to use for the lookup (-p option)
65  */
66 static char *public_key;
67
68 /**
69  * Set to GNUNET_GNS_LO_LOCAL_MASTER if we are looking up in the master zone.
70  */
71 static enum GNUNET_GNS_LocalOptions local_options;
72
73 /**
74  * raw output
75  */
76 static int raw;
77
78 /**
79  * Requested record type.
80  */
81 static int rtype;
82
83 /**
84  * Handle to lookup request
85  */
86 static struct GNUNET_GNS_LookupRequest *lookup_request;
87
88 /**
89  * Lookup an ego with the identity service.
90  */
91 static struct GNUNET_IDENTITY_EgoLookup *el;
92
93 /**
94  * Handle for identity service.
95  */
96 static struct GNUNET_IDENTITY_Handle *identity;
97
98 /**
99  * Active operation on identity service.
100  */
101 static struct GNUNET_IDENTITY_Operation *id_op;
102
103 /**
104  * Task scheduled to handle timeout.
105  */
106 static struct GNUNET_SCHEDULER_Task *tt;
107
108
109 /**
110  * Task run on shutdown.  Cleans up everything.
111  *
112  * @param cls unused
113  */
114 static void
115 do_shutdown (void *cls)
116 {
117   if (NULL != el)
118   {
119     GNUNET_IDENTITY_ego_lookup_cancel (el);
120     el = NULL;
121   }
122   if (NULL != id_op)
123   {
124     GNUNET_IDENTITY_cancel (id_op);
125     id_op = NULL;
126   }
127   if (NULL != lookup_request)
128   {
129     GNUNET_GNS_lookup_cancel (lookup_request);
130     lookup_request = NULL;
131   }
132   if (NULL != identity)
133   {
134     GNUNET_IDENTITY_disconnect (identity);
135     identity = NULL;
136   }
137   if (NULL != gns)
138   {
139     GNUNET_GNS_disconnect (gns);
140     gns = NULL;
141   }
142   if (NULL != tt)
143   {
144     GNUNET_SCHEDULER_cancel (tt);
145     tt = NULL;
146   }
147 }
148
149
150 /**
151  * Task run on timeout. Triggers shutdown.
152  *
153  * @param cls unused
154  */
155 static void
156 do_timeout (void *cls)
157 {
158   tt = NULL;
159   GNUNET_SCHEDULER_shutdown ();
160 }
161
162
163 /**
164  * Function called with the result of a GNS lookup.
165  *
166  * @param cls the 'const char *' name that was resolved
167  * @param rd_count number of records returned
168  * @param rd array of @a rd_count records with the results
169  */
170 static void
171 process_lookup_result (void *cls, uint32_t rd_count,
172                        const struct GNUNET_GNSRECORD_Data *rd)
173 {
174   const char *name = cls;
175   uint32_t i;
176   const char *typename;
177   char* string_val;
178
179   lookup_request = NULL;
180   if (!raw)
181   {
182     if (0 == rd_count)
183       printf ("No results.\n");
184     else
185       printf ("%s:\n",
186               name);
187   }
188   for (i=0; i<rd_count; i++)
189   {
190     if ( (rd[i].record_type != rtype) &&
191          (GNUNET_GNSRECORD_TYPE_ANY != rtype) )
192       continue;
193     typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
194     string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
195                                                    rd[i].data,
196                                                    rd[i].data_size);
197     if (NULL == string_val)
198     {
199       fprintf (stderr,
200                "Record %u of type %d malformed, skipping\n",
201                (unsigned int) i,
202                (int) rd[i].record_type);
203       continue;
204     }
205     if (raw)
206       printf ("%s\n",
207               string_val);
208     else
209       printf ("Got `%s' record: %s\n",
210               typename,
211               string_val);
212     GNUNET_free (string_val);
213   }
214   GNUNET_SCHEDULER_shutdown ();
215 }
216
217
218 /**
219  * Perform the actual resolution, starting with the zone
220  * identified by the given public key and the shorten zone.
221  *
222  * @param pkey public key to use for the zone, can be NULL
223  * @param shorten_key private key used for shortening, can be NULL
224  */
225 static void
226 lookup_with_keys (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
227                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key)
228 {
229   if (NULL != lookup_type)
230     rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
231   else
232     rtype = GNUNET_DNSPARSER_TYPE_A;
233   if (UINT32_MAX == rtype)
234   {
235     fprintf (stderr,
236              _("Invalid typename specified, assuming `ANY'\n"));
237     rtype = GNUNET_GNSRECORD_TYPE_ANY;
238   }
239
240   if (NULL != lookup_name)
241   {
242     lookup_request = GNUNET_GNS_lookup (gns,
243                                         lookup_name,
244                                         pkey,
245                                         rtype,
246                                         local_options,
247                                         shorten_key,
248                                         &process_lookup_result,
249                                         lookup_name);
250   }
251   else
252   {
253     fprintf (stderr,
254              _("Please specify name to lookup!\n"));
255     GNUNET_SCHEDULER_shutdown ();
256     return;
257   }
258 }
259
260
261 /**
262  * Method called to with the ego we are to use for shortening
263  * during the lookup.
264  *
265  * @param cls closure contains the public key to use
266  * @param ego ego handle, NULL if not found
267  * @param ctx context for application to store data for this ego
268  *                 (during the lifetime of this process, initially NULL)
269  * @param name name assigned by the user for this ego,
270  *                   NULL if the user just deleted the ego and it
271  *                   must thus no longer be used
272  */
273 static void
274 identity_shorten_cb (void *cls,
275                      struct GNUNET_IDENTITY_Ego *ego,
276                      void **ctx,
277                      const char *name)
278 {
279   struct GNUNET_CRYPTO_EcdsaPublicKey *pkeym = cls;
280
281   id_op = NULL;
282   if (NULL == ego)
283     lookup_with_keys (pkeym, NULL);
284   else
285     lookup_with_keys (pkeym,
286                       GNUNET_IDENTITY_ego_get_private_key (ego));
287   GNUNET_free (pkeym);
288 }
289
290
291 /**
292  * Perform the actual resolution, starting with the zone
293  * identified by the given public key.
294  *
295  * @param pkey public key to use for the zone
296  */
297 static void
298 lookup_with_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
299 {
300   struct GNUNET_CRYPTO_EcdsaPublicKey *pkeym;
301
302   GNUNET_assert (NULL != pkey);
303   pkeym = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
304   *pkeym = *pkey;
305   GNUNET_break (NULL == id_op);
306   id_op = GNUNET_IDENTITY_get (identity,
307                                "gns-short",
308                                &identity_shorten_cb,
309                                pkeym);
310   if (NULL == id_op)
311   {
312     GNUNET_break (0);
313     lookup_with_keys (pkey, NULL);
314   }
315 }
316
317
318 /**
319  * Method called to with the ego we are to use for the lookup,
320  * when the ego is determined by a name.
321  *
322  * @param cls closure (NULL, unused)
323  * @param ego ego handle, NULL if not found
324  */
325 static void
326 identity_zone_cb (void *cls,
327                   const struct GNUNET_IDENTITY_Ego *ego)
328 {
329   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
330
331   el = NULL;
332   if (NULL == ego)
333   {
334     fprintf (stderr,
335              _("Ego for `%s' not found, cannot perform lookup.\n"),
336              zone_ego_name);
337     GNUNET_SCHEDULER_shutdown ();
338   }
339   else
340   {
341     GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
342     lookup_with_public_key (&pkey);
343   }
344   GNUNET_free_non_null (zone_ego_name);
345   zone_ego_name = NULL;
346 }
347
348
349 /**
350  * Method called to with the ego we are to use for the lookup,
351  * when the ego is the one for the default master zone.
352  *
353  * @param cls closure (NULL, unused)
354  * @param ego ego handle, NULL if not found
355  * @param ctx context for application to store data for this ego
356  *                 (during the lifetime of this process, initially NULL)
357  * @param name name assigned by the user for this ego,
358  *                   NULL if the user just deleted the ego and it
359  *                   must thus no longer be used
360  */
361 static void
362 identity_master_cb (void *cls,
363                     struct GNUNET_IDENTITY_Ego *ego,
364                     void **ctx,
365                     const char *name)
366 {
367   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
368   const char *dot;
369
370   id_op = NULL;
371   if (NULL == ego)
372   {
373     fprintf (stderr,
374              _("Ego for `gns-master' not found, cannot perform lookup.  Did you run gnunet-gns-import.sh?\n"));
375     GNUNET_SCHEDULER_shutdown ();
376     return;
377   }
378   GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
379   /* main name is our own master zone, do no look for that in the DHT */
380   local_options = GNUNET_GNS_LO_LOCAL_MASTER;
381
382   /* if the name is of the form 'label.gnu', never go to the DHT */
383   dot = NULL;
384   if (NULL != lookup_name)
385     dot = strchr (lookup_name, '.');
386   if ( (NULL != dot) &&
387        (0 == strcasecmp (dot, ".gnu")) )
388     local_options = GNUNET_GNS_LO_NO_DHT;
389   lookup_with_public_key (&pkey);
390 }
391
392
393 /**
394  * Main function that will be run.
395  *
396  * @param cls closure
397  * @param args remaining command-line arguments
398  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
399  * @param c configuration
400  */
401 static void
402 run (void *cls,
403      char *const *args,
404      const char *cfgfile,
405      const struct GNUNET_CONFIGURATION_Handle *c)
406 {
407   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
408
409   cfg = c;
410   gns = GNUNET_GNS_connect (cfg);
411   identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
412   if (NULL == gns)
413   {
414     fprintf (stderr,
415              _("Failed to connect to GNS\n"));
416     return;
417   }
418   tt = GNUNET_SCHEDULER_add_delayed (timeout,
419                                      &do_timeout, NULL);
420   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
421   if (NULL != public_key)
422   {
423     if (GNUNET_OK !=
424         GNUNET_CRYPTO_ecdsa_public_key_from_string (public_key,
425                                                   strlen (public_key),
426                                                   &pkey))
427     {
428       fprintf (stderr,
429                _("Public key `%s' is not well-formed\n"),
430                public_key);
431       GNUNET_SCHEDULER_shutdown ();
432       return;
433     }
434     lookup_with_public_key (&pkey);
435     return;
436   }
437   if (NULL != zone_ego_name)
438   {
439     el = GNUNET_IDENTITY_ego_lookup (cfg,
440                                      zone_ego_name,
441                                      &identity_zone_cb,
442                                      NULL);
443     return;
444   }
445   if ( (NULL != lookup_name) &&
446        (strlen (lookup_name) > 4) &&
447        (0 == strcmp (".zkey",
448                      &lookup_name[strlen (lookup_name) - 4])) )
449   {
450     /* no zone required, use 'anonymous' zone */
451     GNUNET_CRYPTO_ecdsa_key_get_public (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
452                                       &pkey);
453     lookup_with_public_key (&pkey);
454   }
455   else
456   {
457     GNUNET_break (NULL == id_op);
458     id_op = GNUNET_IDENTITY_get (identity,
459                                  "gns-master",
460                                  &identity_master_cb,
461                                  NULL);
462     GNUNET_assert (NULL != id_op);
463   }
464 }
465
466
467 /**
468  * The main function for gnunet-gns.
469  *
470  * @param argc number of arguments from the command line
471  * @param argv command line arguments
472  * @return 0 ok, 1 on error
473  */
474 int
475 main (int argc, char *const *argv)
476 {
477   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
478     {'u', "lookup", "NAME",
479       gettext_noop ("Lookup a record for the given name"), 1,
480       &GNUNET_GETOPT_set_string, &lookup_name},
481     {'t', "type", "TYPE",
482       gettext_noop ("Specify the type of the record to lookup"), 1,
483       &GNUNET_GETOPT_set_string, &lookup_type},
484     { 'T', "timeout", "DELAY",
485       gettext_noop ("Specify timeout for the lookup"), 1,
486       &GNUNET_GETOPT_set_relative_time, &timeout },
487     {'r', "raw", NULL,
488       gettext_noop ("No unneeded output"), 0,
489       &GNUNET_GETOPT_set_one, &raw},
490     {'p', "public-key", "PKEY",
491       gettext_noop ("Specify the public key of the zone to lookup the record in"), 1,
492       &GNUNET_GETOPT_set_string, &public_key},
493     {'z', "zone", "NAME",
494       gettext_noop ("Specify the name of the ego of the zone to lookup the record in"), 1,
495       &GNUNET_GETOPT_set_string, &zone_ego_name},
496     GNUNET_GETOPT_OPTION_END
497   };
498   int ret;
499
500   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
501   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
502     return 2;
503
504   GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
505   ret =
506       (GNUNET_OK ==
507        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns",
508                            _("GNUnet GNS resolver tool"),
509                            options,
510                            &run, NULL)) ? 0 : 1;
511   GNUNET_free ((void*) argv);
512   return ret;
513 }
514
515 /* end of gnunet-gns.c */