fix #3275 with solution from https://gnunet.org/bugs/view.php?id=3275#c8029
[oweals/gnunet.git] / src / namecache / gnunet-namecache.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
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_dnsparser_lib.h"
31 #include "gnunet_identity_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_namecache_service.h"
34
35
36 /**
37  * Handle to the namecache.
38  */
39 static struct GNUNET_NAMECACHE_Handle *ns;
40
41 /**
42  * Queue entry for the 'query' operation.
43  */
44 static struct GNUNET_NAMECACHE_QueueEntry *qe;
45
46 /**
47  * Name (label) of the records to list.
48  */
49 static char *name;
50
51 /**
52  * Public key of the zone to look in.
53  */
54 static struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
55
56 /**
57  * Public key of the zone to look in, in ASCII.
58  */
59 static char *pkey;
60
61 /**
62  * Global return value
63  */
64 static int ret;
65
66
67 /**
68  * Task run on shutdown.  Cleans up everything.
69  *
70  * @param cls unused
71  * @param tc scheduler context
72  */
73 static void
74 do_shutdown (void *cls,
75              const struct GNUNET_SCHEDULER_TaskContext *tc)
76 {
77   if (NULL != qe)
78   {
79     GNUNET_NAMECACHE_cancel (qe);
80     qe = NULL;
81   }
82   if (NULL != ns)
83   {
84     GNUNET_NAMECACHE_disconnect (ns);
85     ns = NULL;
86   }
87 }
88
89
90 /**
91  * Process a record that was stored in the namecache in a block.
92  *
93  * @param cls closure, NULL
94  * @param rd_len number of entries in @a rd array
95  * @param rd array of records with data to store
96  */
97 static void
98 display_records_from_block (void *cls,
99                             unsigned int rd_len,
100                             const struct GNUNET_GNSRECORD_Data *rd)
101 {
102   const char *typestring;
103   char *s;
104   unsigned int i;
105
106   if (0 == rd_len)
107   {
108     FPRINTF (stdout,
109              _("No records found for `%s'"),
110              name);
111     return;
112   }
113   FPRINTF (stdout,
114            "%s:\n",
115            name);
116   for (i=0;i<rd_len;i++)
117   {
118     typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
119     s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
120                                           rd[i].data,
121                                           rd[i].data_size);
122     if (NULL == s)
123     {
124       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
125                (unsigned int) rd[i].record_type);
126       continue;
127     }
128     FPRINTF (stdout,
129              "\t%s: %s\n",
130              typestring,
131              s);
132     GNUNET_free (s);
133   }
134   FPRINTF (stdout, "%s", "\n");
135 }
136
137
138 /**
139  * Display block obtained from listing (by name).
140  *
141  * @param cls NULL
142  * @param block NULL if not found
143  */
144 static void
145 handle_block (void *cls,
146               const struct GNUNET_GNSRECORD_Block *block)
147 {
148   qe = NULL;
149   if (NULL == block)
150   {
151     fprintf (stderr,
152              "No matching block found\n");
153   }
154   else if (GNUNET_OK !=
155            GNUNET_GNSRECORD_block_decrypt (block,
156                                            &pubkey,
157                                            name,
158                                            &display_records_from_block,
159                                            NULL))
160   {
161     fprintf (stderr,
162              "Failed to decrypt block!\n");
163   }
164   GNUNET_SCHEDULER_shutdown ();
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  */
176 static void
177 run (void *cls, char *const *args, const char *cfgfile,
178      const struct GNUNET_CONFIGURATION_Handle *cfg)
179 {
180   struct GNUNET_HashCode dhash;
181
182   if (NULL == pkey)
183   {
184     fprintf (stderr,
185              _("You must specify which zone should be accessed\n"));
186     return;
187   }
188
189   if (GNUNET_OK !=
190       GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey,
191                                                   strlen (pkey),
192                                                   &pubkey))
193   {
194     fprintf (stderr,
195              _("Invalid public key for reverse lookup `%s'\n"),
196              pkey);
197     GNUNET_SCHEDULER_shutdown ();
198     return;
199   }
200   if (NULL == name)
201   {
202     fprintf (stderr,
203              _("You must specify a name\n"));
204     return;
205   }
206
207
208   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
209                                 &do_shutdown,
210                                 NULL);
211   ns = GNUNET_NAMECACHE_connect (cfg);
212   GNUNET_GNSRECORD_query_from_public_key (&pubkey,
213                                           name,
214                                           &dhash);
215   qe = GNUNET_NAMECACHE_lookup_block (ns,
216                                       &dhash,
217                                       &handle_block,
218                                       NULL);
219 }
220
221
222 /**
223  * The main function for gnunet-namecache.
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  */
229 int
230 main (int argc, char *const *argv)
231 {
232   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
233     {'n', "name", "NAME",
234      gettext_noop ("name of the record to add/delete/display"), 1,
235      &GNUNET_GETOPT_set_string, &name},
236     {'z', "zone", "PKEY",
237      gettext_noop ("spezifies the public key of the zone to look in"), 1,
238      &GNUNET_GETOPT_set_string, &pkey},
239     GNUNET_GETOPT_OPTION_END
240   };
241
242   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
243     return 2;
244
245   GNUNET_log_setup ("gnunet-namecache", "WARNING", NULL);
246   if (GNUNET_OK !=
247       GNUNET_PROGRAM_run (argc, argv, "gnunet-namecache",
248                           _("GNUnet zone manipulation tool"),
249                           options,
250                           &run, NULL))
251   {
252     GNUNET_free ((void*) argv);
253     return 1;
254   }
255   GNUNET_free ((void*) argv);
256   return ret;
257 }
258
259 /* end of gnunet-namecache.c */