GNUnet 0.22.2
gnunet-namestore-zonefile.c
Go to the documentation of this file.
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 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
29
30#define MAX_RECORDS_PER_NAME 50
31
35#define MAX_ZONEFILE_LINE_LEN 4096
36
40#define MAX_ZONEFILE_RECORD_DATA_LEN 2048
41
47
52
57
61static unsigned int rd_count = 0;
62
66static int ret = 0;
67
71static char *ego_name = NULL;
72
76static char *res;
77
81static unsigned int published_sets = 0;
82
86static unsigned int published_records = 0;
87
88
93
98
103
108
113
118
122static const struct GNUNET_CONFIGURATION_Handle *cfg;
123
128
132static int state;
133
135{
136
137 /* Uninitialized */
139
140 /* The initial state */
142
143 /* The $ORIGIN has changed */
145
146 /* The record name/label has changed */
148
150
151
157static void
158do_shutdown (void *cls)
159{
160 (void) cls;
161 if (NULL != ego_name)
163 if (NULL != el)
164 {
166 el = NULL;
167 }
168 if (NULL != ns_qe)
170 if (NULL != id_op)
172 if (NULL != ns)
174 if (NULL != id)
176 for (int i = 0; i < rd_count; i++)
177 {
178 void *rd_ptr = (void*) rd[i].data;
179 GNUNET_free (rd_ptr);
180 }
181 if (NULL != parse_task)
183}
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 occurrence 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
223
224static char*
225next_token (char *token)
226{
227 char *next = token;
228 while (*next == ' ')
229 next++;
230 return next;
231}
232
233
234static int
235parse_ttl (char *token, struct GNUNET_TIME_Relative *pttl)
236{
237 char *next;
238 unsigned int ttl_tmp;
239
240 next = strchr (token, ';');
241 if (NULL != next)
242 next[0] = '\0';
243 next = strchr (token, ' ');
244 if (NULL != next)
245 next[0] = '\0';
246 if (1 != sscanf (token, "%u", &ttl_tmp))
247 {
248 fprintf (stderr, "Unable to parse TTL `%s'\n", token);
249 return GNUNET_SYSERR;
250 }
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TTL is: %u\n", ttl_tmp);
252 pttl->rel_value_us = ttl_tmp * 1000 * 1000;
253 return GNUNET_OK;
254}
255
256
257static int
258parse_origin (char *token, char *porigin)
259{
260 char *next;
261 next = strchr (token, ';');
262 if (NULL != next)
263 next[0] = '\0';
264 next = strchr (token, ' ');
265 if (NULL != next)
266 next[0] = '\0';
267 strcpy (porigin, token);
268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin is: %s\n", porigin);
269 return GNUNET_OK;
270}
271
272
273static void
275 enum GNUNET_ErrorCode ec)
276{
277 id_op = NULL;
278 if (GNUNET_EC_NONE != ec)
279 {
280 fprintf (stderr, "Error: %s\n", GNUNET_ErrorCode_get_hint (ec));
281 ret = 1;
283 return;
284 }
286 zone_pkey = *pk;
288}
289
290
291static void
292origin_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
293{
294
295 el = NULL;
296
297 if (NULL == ego)
298 {
300 "$ORIGIN %s does not exist, creating...\n", ego_name);
302 GNUNET_PUBLIC_KEY_TYPE_ECDSA, // FIXME make configurable
304 NULL);
305 return;
306 }
310}
311
312
313static void
315{
316 ns_qe = NULL;
317 if (GNUNET_EC_NONE != ec)
318 {
319 fprintf (stderr,
320 _ ("Failed to store records...\n"));
322 ret = -1;
323 }
325 {
326 if (NULL != ego_name)
329 if (ego_name[strlen (ego_name) - 1] == '.')
330 ego_name[strlen (ego_name) - 1] = '\0';
332 "Changing origin to %s\n", ego_name);
334 &origin_lookup_cb, NULL);
335 return;
336 }
338}
339
340
357static void
358parse (void *cls)
359{
360 char buf[MAX_ZONEFILE_LINE_LEN];
362 char *next;
363 char *token;
364 char *payload_pos;
365 static char lastname[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
367 void *data;
368 size_t data_size;
369 int ttl_line = 0;
370 int type;
371 int bracket_unclosed = 0;
372 int quoted = 0;
373 int ln = 0;
374
375 parse_task = NULL;
376 /* use filename provided as 1st argument (stdin by default) */
377 while ((res = fgets (buf, sizeof(buf), stdin))) /* read each line of input */
378 {
379 ln++;
380 ttl_line = 0;
381 token = trim (buf);
383 "Trimmed line (bracket %s): `%s'\n",
384 (bracket_unclosed > 0) ? "unclosed" : "closed",
385 token);
386 if ((0 == strlen (token)) ||
387 ((1 == strlen (token)) && (' ' == *token)))
388 continue; // I guess we can safely ignore blank lines
389 if (bracket_unclosed == 0)
390 {
391 /* Payload is already parsed */
392 payload_pos = payload;
393 /* Find space */
394 next = strchr (token, ' ');
395 if (NULL == next)
396 {
397 fprintf (stderr, "Error at line %u: %s\n", ln, token);
398 ret = 1;
400 return;
401 }
402 next[0] = '\0';
403 next++;
404 if (0 == (strcmp (token, "$ORIGIN")))
405 {
407 token = next_token (next);
408 }
409 else if (0 == (strcmp (token, "$TTL")))
410 {
411 ttl_line = 1;
412 token = next_token (next);
413 }
414 else
415 {
416 if (0 == strcmp (token, "IN")) // Inherit name from before
417 {
419 "Old name: %s\n", lastname);
420 strcpy (newname, lastname);
421 token[strlen (token)] = ' ';
422 }
423 else if (token[strlen (token) - 1] != '.') // no fqdn
424 {
425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: %s\n", token);
426 if (GNUNET_DNSPARSER_MAX_LABEL_LENGTH < strlen (token))
427 {
428 fprintf (stderr,
429 _ ("Name `%s' is too long\n"),
430 token);
431 ret = 1;
433 return;
434 }
435 strcpy (newname, token);
436 token = next_token (next);
437 }
438 else if (0 == strcmp (token, origin))
439 {
440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: @\n");
441 strcpy (newname, "@");
442 token = next_token (next);
443 }
444 else
445 {
446 if (strlen (token) < strlen (origin))
447 {
448 fprintf (stderr, "Wrong origin: %s (expected %s)\n", token, origin);
449 break; // FIXME error?
450 }
451 if (0 != strcmp (token + (strlen (token) - strlen (origin)), origin))
452 {
453 fprintf (stderr, "Wrong origin: %s (expected %s)\n", token, origin);
454 break;
455 }
456 token[strlen (token) - strlen (origin) - 1] = '\0';
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New name: %s\n", token);
458 if (GNUNET_DNSPARSER_MAX_LABEL_LENGTH < strlen (token))
459 {
460 fprintf (stderr,
461 _ ("Name `%s' is too long\n"),
462 token);
463 ret = 1;
465 return;
466 }
467 strcpy (newname, token);
468 token = next_token (next);
469 }
470 if (0 != strcmp (newname, lastname) &&
471 (0 < rd_count))
472 {
474 "Name changed %s->%s, storing record set of %u elements\n",
475 lastname, newname,
476 rd_count);
478 }
479 else
480 {
481 strcpy (lastname, newname);
482 }
483 }
484
485 if (ttl_line)
486 {
487 if (GNUNET_SYSERR == parse_ttl (token, &ttl))
488 {
489 fprintf (stderr, _ ("Failed to parse $TTL\n"));
490 ret = 1;
492 return;
493 }
494 continue;
495 }
497 {
498 if (GNUNET_SYSERR == parse_origin (token, origin))
499 {
500 fprintf (stderr, _ ("Failed to parse $ORIGIN from %s\n"), token);
501 ret = 1;
503 return;
504 }
505 break;
506 }
507 if (ZS_READY == state)
508 {
509 fprintf (stderr,
510 _ (
511 "You must provide $ORIGIN in your zonefile or via arguments (--zone)!\n"));
512 ret = 1;
514 return;
515 }
516 // This is a record, let's go
518 {
519 fprintf (stderr,
520 _ ("Only %u records per unique name supported.\n"),
522 ret = 1;
524 return;
525 }
528 next = strchr (token, ' ');
529 if (NULL == next)
530 {
531 fprintf (stderr, "Error, last token: %s\n", token);
532 ret = 1;
534 break;
535 }
536 next[0] = '\0';
537 next++;
538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "class is: %s\n", token);
539 while (*next == ' ')
540 next++;
541 token = next;
542 next = strchr (token, ' ');
543 if (NULL == next)
544 {
545 fprintf (stderr, "Error\n");
546 break;
547 }
548 next[0] = '\0';
549 next++;
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "type is: %s\n", token);
553 while (*next == ' ')
554 next++;
555 token = next;
556 }
557 for (int i = 0; i < strlen (token); i++)
558 {
559 if (token[i] == '"')
560 quoted = ! quoted;
561 if ((token[i] == '(') && ! quoted)
562 bracket_unclosed++;
563 if ((token[i] == ')') && ! quoted)
564 bracket_unclosed--;
565 }
566 memcpy (payload_pos, token, strlen (token));
567 payload_pos += strlen (token);
568 if (bracket_unclosed > 0)
569 {
570 *payload_pos = ' ';
571 payload_pos++;
572 continue;
573 }
574 *payload_pos = '\0';
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "data is: %s\n\n", payload);
576 if (GNUNET_OK !=
578 &data,
579 &data_size))
580 {
581 fprintf (stderr,
582 _ ("Data `%s' invalid\n"),
583 payload);
584 ret = 1;
586 return;
587 }
588 rd[rd_count].data = data;
590 if (ZS_NAME_CHANGED == state)
591 break;
592 rd_count++;
593 }
594 if (rd_count > 0)
595 {
597 &zone_pkey,
598 lastname,
599 rd_count,
600 rd,
602 NULL);
605 for (int i = 0; i < rd_count; i++)
606 {
607 data = (void*) rd[i].data;
609 }
610 if (ZS_NAME_CHANGED == state)
611 {
612 rd[0] = rd[rd_count]; // recover last rd parsed.
613 rd_count = 1;
614 strcpy (lastname, newname);
616 }
617 else
618 rd_count = 0;
619 return;
620 }
622 {
623 if (NULL != ego_name)
626 if (ego_name[strlen (ego_name) - 1] == '.')
627 ego_name[strlen (ego_name) - 1] = '\0';
629 "Changing origin to %s\n", ego_name);
631 &origin_lookup_cb, NULL);
632 return;
633 }
634 printf ("Published %u records sets with total %u records\n",
637}
638
639
640static void
641identity_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
642{
643
644 el = NULL;
645 if (NULL == ego)
646 {
647 if (NULL != ego_name)
648 {
649 fprintf (stderr,
650 _ ("Ego `%s' not known to identity service\n"),
651 ego_name);
652
653 }
655 ret = -1;
656 return;
657 }
659 sprintf (origin, "%s.", ego_name);
662}
663
664
665static void
666run (void *cls,
667 char *const *args,
668 const char *cfgfile,
669 const struct GNUNET_CONFIGURATION_Handle *_cfg)
670{
671 cfg = _cfg;
674 if (NULL == ns)
675 {
676 fprintf (stderr,
677 _ ("Failed to connect to NAMESTORE\n"));
678 return;
679 }
680 id = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
681 if (NULL == id)
682 {
683 fprintf (stderr,
684 _ ("Failed to connect to IDENTITY\n"));
685 return;
686 }
687 if (NULL != ego_name)
689 else
691 state = ZS_READY;
692}
693
694
702int
703main (int argc, char *const *argv)
704{
707 "zone",
708 "EGO",
710 "name of the ego controlling the zone"),
711 &ego_name),
713 };
714 int lret;
715
716 GNUNET_log_setup ("gnunet-namestore-dbtool", "WARNING", NULL);
717 if (GNUNET_OK !=
719 argc,
720 argv,
721 "gnunet-namestore-zonefile",
722 _ (
723 "GNUnet namestore database manipulation tool"),
724 options,
725 &run,
726 NULL)))
727 {
728 return lret;
729 }
730 return ret;
731}
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#define gettext_noop(String)
Definition: gettext.h:74
static char * line
Desired phone line (string to be converted to a hash).
static char * data
The data to insert into the dht.
struct GNUNET_CRYPTO_PrivateKey pk
Private key from command line option, or NULL.
static struct GNUNET_NAMESTORE_QueueEntry * ns_qe
Queue entry for the 'add' operation.
static struct GNUNET_IDENTITY_Operation * id_op
Origin create operations.
static struct GNUNET_CRYPTO_PrivateKey zone_pkey
Private key for the our zone.
static void identity_cb(void *cls, struct GNUNET_IDENTITY_Ego *ego)
static void parse(void *cls)
Main function that will be run.
static unsigned int published_records
Statistics, how many records published in aggregate.
static void origin_create_cb(void *cls, const struct GNUNET_CRYPTO_PrivateKey *pk, enum GNUNET_ErrorCode ec)
static const struct GNUNET_CONFIGURATION_Handle * cfg
Current configurataion.
static struct GNUNET_SCHEDULER_Task * parse_task
Scheduled parse task.
static struct GNUNET_TIME_Relative ttl
Current record $TTL to use.
#define MAX_RECORDS_PER_NAME
static int ret
Return code.
static void do_shutdown(void *cls)
Task run on shutdown.
static struct GNUNET_IDENTITY_EgoLookup * el
Handle to identity lookup.
static char * ego_name
Name of the ego.
#define MAX_ZONEFILE_LINE_LEN
Maximum length of a zonefile line.
static char origin[GNUNET_DNSPARSER_MAX_NAME_LENGTH]
Current origin.
#define MAX_ZONEFILE_RECORD_DATA_LEN
FIXME: Soft limit this?
static int state
The current state of the parser.
static void add_continuation(void *cls, enum GNUNET_ErrorCode ec)
static unsigned int rd_count
Number of records for currently parsed set.
static int parse_origin(char *token, char *porigin)
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *_cfg)
static struct GNUNET_NAMESTORE_Handle * ns
Handle to the namestore.
static char * res
Currently read line or NULL on EOF.
static struct GNUNET_IDENTITY_Handle * id
Handle to IDENTITY.
static char * trim(char *line)
int main(int argc, char *const *argv)
The main function for gnunet-namestore-dbtool.
static void origin_lookup_cb(void *cls, struct GNUNET_IDENTITY_Ego *ego)
static struct GNUNET_GNSRECORD_Data rd[50]
The record data under a single label.
static int parse_ttl(char *token, struct GNUNET_TIME_Relative *pttl)
static char * next_token(char *token)
static unsigned int published_sets
Statistics, how many published record sets.
static uint32_t type
Type string converted to DNS type value.
static size_t data_size
Number of bytes in data.
static unsigned long long payload
How much data are we currently storing in the database?
Plugin API for the namestore database backend.
#define GNUNET_DNSPARSER_MAX_LABEL_LENGTH
Maximum length of a label in DNS.
#define GNUNET_DNSPARSER_MAX_NAME_LENGTH
Maximum length of a name in DNS.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_string(char shortName, const char *name, const char *argumentHelp, const char *description, char **str)
Allow user to specify a string.
uint32_t GNUNET_GNSRECORD_typename_to_number(const char *dns_typename)
Convert a type name (e.g.
Definition: gnsrecord.c:192
int GNUNET_GNSRECORD_string_to_value(uint32_t type, const char *s, void **data, size_t *data_size)
Convert human-readable version of the value s of a record of type type to the respective binary repre...
Definition: gnsrecord.c:169
@ GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION
This expiration time of the record is a relative time (not an absolute time).
struct GNUNET_IDENTITY_Operation * GNUNET_IDENTITY_create(struct GNUNET_IDENTITY_Handle *id, const char *name, const struct GNUNET_CRYPTO_PrivateKey *privkey, enum GNUNET_CRYPTO_KeyType ktype, GNUNET_IDENTITY_CreateContinuation cont, void *cont_cls)
Create a new ego with the given name.
Definition: identity_api.c:561
const struct GNUNET_CRYPTO_PrivateKey * GNUNET_IDENTITY_ego_get_private_key(const struct GNUNET_IDENTITY_Ego *ego)
Obtain the ECC key associated with a ego.
Definition: identity_api.c:517
struct GNUNET_IDENTITY_EgoLookup * GNUNET_IDENTITY_ego_lookup(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name, GNUNET_IDENTITY_EgoCallback cb, void *cb_cls)
Lookup an ego by name.
struct GNUNET_IDENTITY_Handle * GNUNET_IDENTITY_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_IDENTITY_Callback cb, void *cb_cls)
Connect to the identity service.
Definition: identity_api.c:487
void GNUNET_IDENTITY_cancel(struct GNUNET_IDENTITY_Operation *op)
Cancel an identity operation.
Definition: identity_api.c:715
void GNUNET_IDENTITY_ego_lookup_cancel(struct GNUNET_IDENTITY_EgoLookup *el)
Abort ego lookup attempt.
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:732
#define GNUNET_log(kind,...)
@ GNUNET_PUBLIC_KEY_TYPE_ECDSA
The identity type.
@ GNUNET_OK
@ GNUNET_SYSERR
enum GNUNET_GenericReturnValue GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_set_store(struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_PrivateKey *pkey, const char *label, unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls)
Store an item in the namestore.
void GNUNET_NAMESTORE_disconnect(struct GNUNET_NAMESTORE_Handle *h)
Disconnect from the namestore service (and free associated resources).
void GNUNET_NAMESTORE_cancel(struct GNUNET_NAMESTORE_QueueEntry *qe)
Cancel a namestore operation.
struct GNUNET_NAMESTORE_Handle * GNUNET_NAMESTORE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the namestore service.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:407
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:980
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1304
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
const char * GNUNET_ErrorCode_get_hint(enum GNUNET_ErrorCode ec)
Returns a hint for a given error code.
GNUNET_ErrorCode
Taler error codes.
@ GNUNET_EC_NONE
No error (success).
A private key for an identity as per LSD0001.
Definition of a command line option.
uint32_t record_type
Type of the GNS/DNS record.
const void * data
Binary value stored in the DNS record.
size_t data_size
Number of bytes in data.
enum GNUNET_GNSRECORD_Flags flags
Flags for the record.
uint64_t expiration_time
Expiration time for the DNS record.
Handle for ego lookup.
Handle for an ego.
Definition: identity.h:37
Handle for the service.
Definition: identity_api.c:97
Handle for an operation with the identity service.
Definition: identity_api.c:41
Connection to the NAMESTORE service.
An QueueEntry used to store information for a pending NAMESTORE record operation.
Definition: namestore_api.c:49
Entry in list of pending tasks.
Definition: scheduler.c:136
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition: scheduler.c:140
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.