2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @brief command line tool to manipulate the local zone
23 * @author Christian Grothoff
27 * - allow users to set record options (not just 'RF_AUTHORITY')
29 * - parsing SOA, PTR and MX value specifications (and define format!)
30 * - add options to list/lookup individual records
31 * - add option to shorten name (lookup PKEY, then lookup name by zone,
32 * then possibly lookup PSEU for the zone and update our zone)
35 #include <gnunet_util_lib.h>
36 #include <gnunet_dnsparser_lib.h>
37 #include <gnunet_namestore_service.h>
40 * Handle to the namestore.
42 static struct GNUNET_NAMESTORE_Handle *ns;
45 * Hash of the public key of our zone.
47 static GNUNET_HashCode zone;
50 * Private key for the our zone.
52 static struct GNUNET_CRYPTO_RsaPrivateKey *zone_pkey;
55 * Keyfile to manipulate.
60 * Desired action is to add a record.
65 * Queue entry for the 'add' operation.
67 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
70 * Desired action is to list records.
75 * List iterator for the 'list' operation.
77 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
80 * Desired action is to remove a record.
85 * Queue entry for the 'del' operation.
87 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
90 * Name of the records to add/list/remove.
95 * Value of the record to add/remove.
100 * Type of the record to add/remove, NULL to remove all.
102 static char *typestring;
105 * Desired expiration time.
107 static char *expirationstring;
111 * Task run on shutdown. Cleans up everything.
114 * @param tc scheduler context
117 do_shutdown (void *cls,
118 const struct GNUNET_SCHEDULER_TaskContext *tc)
122 GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO);
125 if (NULL != zone_pkey)
127 GNUNET_CRYPTO_rsa_key_free (zone_pkey);
134 * Continuation called to notify client about result of the
137 * @param cls closure, unused
138 * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
139 * GNUNET_NO if content was already there
140 * GNUNET_YES (or other positive value) on success
141 * @param emsg NULL on success, otherwise an error message
144 add_continuation (void *cls,
149 if (success != GNUNET_YES)
151 _("Adding record failed: %s\n"),
152 (success == GNUNET_NO) ? "record exists" : emsg);
153 if ( (NULL == del_qe) &&
155 GNUNET_SCHEDULER_shutdown ();
160 * Continuation called to notify client about result of the
163 * @param cls closure, unused
164 * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
165 * GNUNET_NO if content was already there
166 * GNUNET_YES (or other positive value) on success
167 * @param emsg NULL on success, otherwise an error message
170 del_continuation (void *cls,
175 if (success != GNUNET_YES)
177 _("Deleting record failed: %s\n"),
179 if ( (NULL == add_qe) &&
181 GNUNET_SCHEDULER_shutdown ();
186 * Process a record that was stored in the namestore.
189 * @param zone_key public key of the zone
190 * @param expire when does the corresponding block in the DHT expire (until
191 * when should we never do a DHT lookup for the same name again)?;
192 * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore,
193 * or the expiration time of the block in the namestore (even if there are zero
194 * records matching the desired record type)
195 * @param name name that is being mapped (at most 255 characters long)
196 * @param rd_count number of entries in 'rd' array
197 * @param rd array of records with data to store
198 * @param signature signature of the record block, NULL if signature is unavailable (i.e.
199 * because the user queried for a particular record type only)
202 display_record (void *cls,
203 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
204 struct GNUNET_TIME_Absolute expire,
207 const struct GNUNET_NAMESTORE_RecordData *rd,
208 const struct GNUNET_CRYPTO_RsaSignature *signature)
213 if ( (NULL == del_qe) &&
215 GNUNET_SCHEDULER_shutdown ();
218 // FIXME: display record!
219 GNUNET_NAMESTORE_zone_iterator_next (list_it);
224 * Main function that will be run.
227 * @param args remaining command-line arguments
228 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
229 * @param cfg configuration
232 run (void *cls, char *const *args, const char *cfgfile,
233 const struct GNUNET_CONFIGURATION_Handle *cfg)
235 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
239 struct in_addr value_a;
240 struct in6_addr value_aaaa;
241 struct GNUNET_TIME_Relative etime;
242 struct GNUNET_NAMESTORE_RecordData rd;
247 _("Option `%s' not given, but I need a zone key file!\n"),
251 zone_pkey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
252 GNUNET_free (keyfile);
254 if (! (add|del|list))
256 /* nothing more to be done */
257 GNUNET_CRYPTO_rsa_key_free (zone_pkey);
261 if (NULL == zone_pkey)
263 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
264 _("Failed to read or create private zone key\n"));
267 GNUNET_CRYPTO_rsa_key_get_public (zone_pkey,
269 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &zone);
271 ns = GNUNET_NAMESTORE_connect (cfg);
274 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
275 _("Failed to connect to namestore\n"));
278 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
280 if (NULL == typestring)
283 type = GNUNET_NAMESTORE_typename_to_number (typestring);
284 if (UINT32_MAX == type)
286 fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
287 GNUNET_SCHEDULER_shutdown ();
289 } else if (add | del)
292 _("Missing option `%s' for operation `%s'\n"),
294 GNUNET_SCHEDULER_shutdown ();
302 fprintf (stderr, _("Need a record type to interpret value `%s'\n"), value);
303 GNUNET_SCHEDULER_shutdown ();
305 case GNUNET_DNSPARSER_TYPE_A:
306 if (1 != inet_pton (AF_INET, value, &value_a))
308 fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
311 GNUNET_SCHEDULER_shutdown ();
315 data_size = sizeof (value_a);
317 case GNUNET_DNSPARSER_TYPE_NS:
319 data_size = strlen (value);
321 case GNUNET_DNSPARSER_TYPE_CNAME:
323 data_size = strlen (value);
325 case GNUNET_DNSPARSER_TYPE_SOA:
327 fprintf (stderr, _("Record type `%s' not implemented yet\n"), typestring);
328 GNUNET_SCHEDULER_shutdown ();
330 case GNUNET_DNSPARSER_TYPE_PTR:
332 fprintf (stderr, _("Record type `%s' not implemented yet\n"), typestring);
333 GNUNET_SCHEDULER_shutdown ();
335 case GNUNET_DNSPARSER_TYPE_MX:
337 fprintf (stderr, _("Record type `%s' not implemented yet\n"), typestring);
338 GNUNET_SCHEDULER_shutdown ();
340 case GNUNET_DNSPARSER_TYPE_TXT:
342 data_size = strlen (value);
344 case GNUNET_DNSPARSER_TYPE_AAAA:
345 if (1 != inet_pton (AF_INET6, value, &value_aaaa))
347 fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
350 GNUNET_SCHEDULER_shutdown ();
354 data_size = sizeof (value_aaaa);
356 case GNUNET_GNS_TYPE_PKEY:
357 fprintf (stderr, _("Record type `%s' not implemented yet\n"), typestring);
358 GNUNET_SCHEDULER_shutdown ();
360 case GNUNET_GNS_TYPE_PSEU:
362 data_size = strlen (value);
367 } else if (add | del)
370 _("Missing option `%s' for operation `%s'\n"),
372 GNUNET_SCHEDULER_shutdown ();
375 if (NULL != expirationstring)
378 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
382 _("Invalid time format `%s'\n"),
384 GNUNET_SCHEDULER_shutdown ();
387 } else if (add | del)
390 _("Missing option `%s' for operation `%s'\n"),
392 GNUNET_SCHEDULER_shutdown ();
400 _("Missing option `%s' for operation `%s'\n"),
402 GNUNET_SCHEDULER_shutdown ();
406 rd.data_size = data_size;
407 rd.record_type = type;
408 rd.expiration = GNUNET_TIME_relative_to_absolute (etime);
409 rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY; // FIXME: not always...
410 add_qe = GNUNET_NAMESTORE_record_create (ns,
422 _("Missing option `%s' for operation `%s'\n"),
424 GNUNET_SCHEDULER_shutdown ();
428 rd.data_size = data_size;
429 rd.record_type = type;
430 rd.expiration = GNUNET_TIME_relative_to_absolute (etime);
431 rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY; // FIXME: not always...
432 del_qe = GNUNET_NAMESTORE_record_create (ns,
441 list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
451 * The main function for gnunet-gns.
453 * @param argc number of arguments from the command line
454 * @param argv command line arguments
455 * @return 0 ok, 1 on error
458 main (int argc, char *const *argv)
460 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
462 gettext_noop ("add record"), 0,
463 &GNUNET_GETOPT_set_one, &add},
464 {'d', "delete", NULL,
465 gettext_noop ("delete record"), 0,
466 &GNUNET_GETOPT_set_one, &del},
467 {'D', "display", NULL,
468 gettext_noop ("display records"), 0,
469 &GNUNET_GETOPT_set_one, &list},
470 {'e', "expiration", "TIME",
471 gettext_noop ("expiration time to use (for adding only)"), 1,
472 &GNUNET_GETOPT_set_string, &expirationstring},
473 {'n', "name", "NAME",
474 gettext_noop ("name of the record to add/delete/display"), 1,
475 &GNUNET_GETOPT_set_string, &name},
476 {'t', "type", "TYPE",
477 gettext_noop ("type of the record to add/delete/display"), 1,
478 &GNUNET_GETOPT_set_string, &typestring},
479 {'V', "value", "VALUE",
480 gettext_noop ("value of the record to add/delete"), 1,
481 &GNUNET_GETOPT_set_string, &value},
482 {'z', "zonekey", "FILENAME",
483 gettext_noop ("filename with the zone key"), 1,
484 &GNUNET_GETOPT_set_string, &keyfile},
485 GNUNET_GETOPT_OPTION_END
490 GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
493 GNUNET_PROGRAM_run (argc, argv, "gnunet-gns",
494 _("GNUnet GNS zone manipulation tool"),
496 &run, NULL)) ? 0 : 1;
501 /* end of gnunet-gns.c */