2 This file is part of GNUnet
3 Copyright (C) 2018 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file src/namestore/gnunet-zoneimport.c
22 * @brief import a DNS zone for publication in GNS, incremental
23 * @author Christian Grothoff
26 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsstub_lib.h>
28 #include <gnunet_dnsparser_lib.h>
29 #include <gnunet_gnsrecord_lib.h>
30 #include <gnunet_namestore_service.h>
31 #include <gnunet_identity_service.h>
35 * Maximum number of queries pending at the same time.
40 * TIME_THRESH is in usecs. How quickly do we submit fresh queries.
41 * Used as an additional throttle.
43 #define TIME_THRESH 10
46 * How often do we retry a query before giving up for good?
52 * Some zones may include authoritative records for other
53 * zones, such as foo.com.uk or bar.com.fr. As for GNS
54 * each dot represents a zone cut, we then need to create a
55 * zone on-the-fly to capture those records properly.
71 * Domain of the zone (i.e. "fr" or "com.fr")
76 * Private key of the zone.
78 struct GNUNET_CRYPTO_EcdsaPrivateKey key;
84 * Record for the request to be stored by GNS.
101 struct GNUNET_GNSRECORD_Data grd;
107 * Request we should make.
112 * Requests are kept in a heap while waiting to be resolved.
114 struct GNUNET_CONTAINER_HeapNode *hn;
117 * Active requests are kept in a DLL.
119 struct Request *next;
122 * Active requests are kept in a DLL.
124 struct Request *prev;
127 * Head of records that should be published in GNS for
130 struct Record *rec_head;
133 * Tail of records that should be published in GNS for
136 struct Record *rec_tail;
139 * Socket used to make the request, NULL if not active.
141 struct GNUNET_DNSSTUB_RequestSocket *rs;
149 * Hostname we are resolving.
154 * Label (without TLD) which we are resolving.
159 * Namestore operation pending for this record.
161 struct GNUNET_NAMESTORE_QueueEntry *qe;
164 * Zone responsible for this request.
166 const struct Zone *zone;
169 * Answer we got back and are currently parsing, or NULL
172 struct GNUNET_DNSPARSER_Packet *p;
175 * At what time does the (earliest) of the returned records
176 * for this name expire? At this point, we need to re-fetch
179 struct GNUNET_TIME_Absolute expires;
182 * Number of bytes in @e raw.
187 * When did we last issue this request?
192 * How often did we issue this query? (And failed, reset
193 * to zero once we were successful.)
198 * random 16-bit DNS query identifier.
205 * Handle to the identity service.
207 static struct GNUNET_IDENTITY_Handle *id;
212 static struct GNUNET_NAMESTORE_Handle *ns;
215 * Context for DNS resolution.
217 static struct GNUNET_DNSSTUB_Context *ctx;
220 * The number of queries that are outstanding
222 static unsigned int pending;
225 * Number of lookups we performed overall.
227 static unsigned int lookups;
230 * How many hostnames did we reject (malformed).
232 static unsigned int rejects;
235 * Number of lookups that failed.
237 static unsigned int failures;
240 * Number of records we found.
242 static unsigned int records;
245 * #GNUNET_YES if we have more work to be read from `stdin`.
247 static int stdin_waiting;
250 * Heap of all requests to perform, sorted by
251 * the time we should next do the request (i.e. by expires).
253 static struct GNUNET_CONTAINER_Heap *req_heap;
256 * Active requests are kept in a DLL.
258 static struct Request *req_head;
261 * Active requests are kept in a DLL.
263 static struct Request *req_tail;
268 static struct GNUNET_SCHEDULER_Task *t;
271 * Head of list of zones we are managing.
273 static struct Zone *zone_head;
276 * Tail of list of zones we are managing.
278 static struct Zone *zone_tail;
282 * Callback for #for_all_records
285 * @param rec a DNS record
288 (*RecordProcessor) (void *cls,
289 const struct GNUNET_DNSPARSER_Record *rec);
293 * Call @a rp for each record in @a p, regardless of
294 * what response section it is in.
296 * @param p packet from DNS
297 * @param rp function to call
298 * @param rp_cls closure for @a rp
301 for_all_records (const struct GNUNET_DNSPARSER_Packet *p,
305 for (unsigned int i=0;i<p->num_answers;i++)
307 struct GNUNET_DNSPARSER_Record *rs = &p->answers[i];
312 for (unsigned int i=0;i<p->num_authority_records;i++)
314 struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i];
319 for (unsigned int i=0;i<p->num_additional_records;i++)
321 struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i];
330 * Free @a req and data structures reachable from it.
332 * @param req request to free
335 free_request (struct Request *req)
339 while (NULL != (rec = req->rec_head))
341 GNUNET_CONTAINER_DLL_remove (req->rec_head,
346 GNUNET_free (req->hostname);
347 GNUNET_free (req->label);
348 GNUNET_free (req->raw);
354 * Process as many requests as possible from the queue.
359 process_queue (void *cls);
363 * Insert @a req into DLL sorted by next fetch time.
365 * @param req request to insert into #req_heap
368 insert_sorted (struct Request *req)
370 req->hn = GNUNET_CONTAINER_heap_insert (req_heap,
372 req->expires.abs_value_us);
373 if (req == GNUNET_CONTAINER_heap_peek (req_heap))
376 GNUNET_SCHEDULER_cancel (t);
377 t = GNUNET_SCHEDULER_add_at (req->expires,
385 * Add record to the GNS record set for @a req.
387 * @param req the request to expand GNS record set for
388 * @param type type to use
389 * @param expiration_time when should @a rec expire
390 * @param data raw data to store
391 * @param data_len number of bytes in @a data
394 add_record (struct Request *req,
396 struct GNUNET_TIME_Absolute expiration_time,
402 rec = GNUNET_malloc (sizeof (struct Record) + data_len);
403 rec->grd.data = &rec[1];
404 rec->grd.expiration_time = expiration_time.abs_value_us;
405 rec->grd.data_size = data_len;
406 rec->grd.record_type = type;
407 rec->grd.flags = GNUNET_GNSRECORD_RF_NONE;
408 GNUNET_memcpy (&rec[1],
411 GNUNET_CONTAINER_DLL_insert (req->rec_head,
418 * Closure for #check_for_glue.
423 * Overall request we are processing.
428 * NS name we are looking for glue for.
433 * Set to #GNUNET_YES if glue was found.
440 * Try to find glue records for a given NS record.
442 * @param cls a `struct GlueClosure *`
443 * @param rec record that may contain glue information
446 check_for_glue (void *cls,
447 const struct GNUNET_DNSPARSER_Record *rec)
449 struct GlueClosure *gc = cls;
453 char ip[INET6_ADDRSTRLEN+1];
454 socklen_t ip_size = (socklen_t) sizeof (ip);
456 if (0 != strcasecmp (rec->name,
459 dst_len = sizeof (dst);
463 case GNUNET_DNSPARSER_TYPE_A:
464 if (sizeof (struct in_addr) != rec->data.raw.data_len)
479 GNUNET_DNSPARSER_builder_add_name (dst,
482 gc->req->hostname)) &&
484 GNUNET_DNSPARSER_builder_add_name (dst,
490 GNUNET_GNSRECORD_TYPE_GNS2DNS,
491 rec->expiration_time,
494 gc->found = GNUNET_YES;
497 case GNUNET_DNSPARSER_TYPE_AAAA:
498 if (sizeof (struct in6_addr) != rec->data.raw.data_len)
513 GNUNET_DNSPARSER_builder_add_name (dst,
516 gc->req->hostname)) &&
518 GNUNET_DNSPARSER_builder_add_name (dst,
524 GNUNET_GNSRECORD_TYPE_GNS2DNS,
525 rec->expiration_time,
528 gc->found = GNUNET_YES;
531 case GNUNET_DNSPARSER_TYPE_CNAME:
533 GNUNET_DNSPARSER_builder_add_name (dst,
536 gc->req->hostname)) &&
538 GNUNET_DNSPARSER_builder_add_name (dst,
541 rec->data.hostname)) )
544 GNUNET_GNSRECORD_TYPE_GNS2DNS,
545 rec->expiration_time,
548 gc->found = GNUNET_YES;
552 /* useless, do nothing */
559 * We received @a rec for @a req. Remember the answer.
561 * @param cls a `struct Request`
562 * @param rec response
565 process_record (void *cls,
566 const struct GNUNET_DNSPARSER_Record *rec)
568 struct Request *req = cls;
573 dst_len = sizeof (dst);
576 if (0 != strcasecmp (rec->name,
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "DNS returned record for `%s' of type %u while resolving `%s'\n",
582 (unsigned int) rec->type,
584 return; /* does not match hostname, might be glue, but
585 not useful for this pass! */
588 GNUNET_TIME_absolute_get_remaining (rec->expiration_time).rel_value_us)
590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591 "DNS returned expired record for `%s'\n",
593 return; /* record expired */
597 case GNUNET_DNSPARSER_TYPE_NS:
599 struct GlueClosure gc;
603 gc.ns = rec->data.hostname;
604 gc.found = GNUNET_NO;
605 for_all_records (req->p,
608 if ( (GNUNET_NO == gc.found) &&
610 GNUNET_DNSPARSER_builder_add_name (dst,
615 GNUNET_DNSPARSER_builder_add_name (dst,
618 rec->data.hostname)) )
620 /* FIXME: actually check if this is out-of-bailiwick,
621 and if not request explicit resolution... */
622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
623 "Converted OOB (`%s') NS record for `%s'\n",
627 GNUNET_GNSRECORD_TYPE_GNS2DNS,
628 rec->expiration_time,
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635 "Converted NS record for `%s' using glue\n",
640 case GNUNET_DNSPARSER_TYPE_CNAME:
642 GNUNET_DNSPARSER_builder_add_name (dst,
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648 "Converting CNAME (`%s') record for `%s'\n",
653 rec->expiration_time,
658 case GNUNET_DNSPARSER_TYPE_DNAME:
659 /* No support for DNAME in GNS yet! FIXME: support later! */
661 "FIXME: not supported: %s DNAME %s\n",
665 case GNUNET_DNSPARSER_TYPE_MX:
667 GNUNET_DNSPARSER_builder_add_mx (dst,
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673 "Converting MX (`%s') record for `%s'\n",
674 rec->data.mx->mxhost,
678 rec->expiration_time,
683 case GNUNET_DNSPARSER_TYPE_SOA:
685 GNUNET_DNSPARSER_builder_add_soa (dst,
690 /* NOTE: GNS does not really use SOAs */
691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692 "Converting SOA record for `%s'\n",
696 rec->expiration_time,
701 case GNUNET_DNSPARSER_TYPE_SRV:
703 GNUNET_DNSPARSER_builder_add_srv (dst,
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 "Converting SRV record for `%s'\n",
713 rec->expiration_time,
718 case GNUNET_DNSPARSER_TYPE_PTR:
720 GNUNET_DNSPARSER_builder_add_name (dst,
725 /* !?: what does a PTR record do in a regular TLD??? */
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Converting PTR record for `%s' (weird)\n",
731 rec->expiration_time,
736 case GNUNET_DNSPARSER_TYPE_CERT:
738 GNUNET_DNSPARSER_builder_add_cert (dst,
743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
744 "Converting CERT record for `%s'\n",
748 rec->expiration_time,
753 /* Rest is 'raw' encoded and just needs to be copied IF
754 the hostname matches the requested name; otherwise we
755 simply cannot use it. */
756 case GNUNET_DNSPARSER_TYPE_A:
757 case GNUNET_DNSPARSER_TYPE_AAAA:
758 case GNUNET_DNSPARSER_TYPE_TXT:
760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761 "Converting record of type %u for `%s'\n",
762 (unsigned int) rec->type,
766 rec->expiration_time,
768 rec->data.raw.data_len);
775 * Continuation called to notify client about result of the
778 * @param cls closure with our `struct Request`
779 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
780 * #GNUNET_NO if content was already there or not found
781 * #GNUNET_YES (or other positive value) on success
782 * @param emsg NULL on success, otherwise an error message
785 store_completed_cb (void *cls,
789 static unsigned int pdot;
790 struct Request *req = cls;
795 if (GNUNET_SYSERR == success)
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798 "Failed to store zone data for `%s': %s\n",
804 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
805 "Stored records under `%s'\n",
808 if (0 == pdot % 1000)
809 fprintf (stderr, ".");
812 while (NULL != (rec = req->rec_head))
814 GNUNET_CONTAINER_DLL_remove (req->rec_head,
823 * Function called with the result of a DNS resolution.
825 * @param cls closure with the `struct Request`
826 * @param dns dns response, never NULL
827 * @param dns_len number of bytes in @a dns
830 process_result (void *cls,
831 const struct GNUNET_TUN_DnsHeader *dns,
834 struct Request *req = cls;
836 struct GNUNET_DNSPARSER_Packet *p;
837 unsigned int rd_count;
839 GNUNET_assert (NULL == req->hn);
843 GNUNET_CONTAINER_DLL_remove (req_head,
847 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
848 "Stub gave up on DNS reply for `%s'\n",
850 if (req->issue_num > MAX_RETRIES)
860 if (req->id != dns->id)
862 GNUNET_CONTAINER_DLL_remove (req_head,
865 GNUNET_DNSSTUB_resolve_cancel (req->rs);
867 p = GNUNET_DNSPARSER_parse ((const char *) dns,
871 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
872 "Failed to parse DNS reply for `%s'\n",
874 if (req->issue_num > MAX_RETRIES)
885 /* import new records */
886 req->issue_num = 0; /* success, reset counter! */
892 GNUNET_DNSPARSER_free_packet (p);
893 /* count records found, determine minimum expiration time */
894 req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
896 for (rec = req->rec_head; NULL != rec; rec = rec->next)
898 struct GNUNET_TIME_Absolute at;
900 at.abs_value_us = rec->grd.expiration_time;
901 req->expires = GNUNET_TIME_absolute_min (req->expires,
905 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
906 "Obtained %u records for `%s'\n",
909 /* Instead of going for SOA, simplified for now to look each
910 day in case we got an empty response */
913 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
914 /* convert records to namestore import format */
916 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(rd_count)];
917 unsigned int off = 0;
919 /* convert linked list into array */
920 for (rec = req->rec_head; NULL != rec; rec =rec->next)
921 rd[off++] = rec->grd;
922 req->qe = GNUNET_NAMESTORE_records_store (ns,
935 * Submit a request to DNS unless we need to slow down because
936 * we are at the rate limit.
938 * @param req request to submit
939 * @return #GNUNET_OK if request was submitted
940 * #GNUNET_NO if request was already submitted
941 * #GNUNET_SYSERR if we are at the rate limit
944 submit_req (struct Request *req)
946 static struct GNUNET_TIME_Absolute last_request;
947 struct GNUNET_TIME_Absolute now;
950 return GNUNET_NO; /* namestore op still pending */
954 return GNUNET_NO; /* already submitted */
956 now = GNUNET_TIME_absolute_get ();
957 if ( (now.abs_value_us - last_request.abs_value_us < TIME_THRESH) ||
958 (pending >= THRESH) )
959 return GNUNET_SYSERR;
960 GNUNET_CONTAINER_DLL_insert (req_head,
963 GNUNET_assert (NULL == req->rs);
964 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
965 "Requesting resolution for `%s'\n",
967 req->rs = GNUNET_DNSSTUB_resolve (ctx,
972 GNUNET_assert (NULL != req->rs);
977 req->time = time (NULL);
983 * Process as many requests as possible from the queue.
988 process_queue (void *cls)
996 req = GNUNET_CONTAINER_heap_peek (req_heap);
999 if (GNUNET_TIME_absolute_get_remaining (req->expires).rel_value_us > 0)
1001 if (GNUNET_OK != submit_req (req))
1003 GNUNET_assert (req ==
1004 GNUNET_CONTAINER_heap_remove_root (req_heap));
1008 req = GNUNET_CONTAINER_heap_peek (req_heap);
1011 if (GNUNET_TIME_absolute_get_remaining (req->expires).rel_value_us > 0)
1013 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1014 "Waiting until %s for next record (`%s') to expire\n",
1015 GNUNET_STRINGS_absolute_time_to_string (req->expires),
1018 GNUNET_SCHEDULER_cancel (t);
1019 t = GNUNET_SCHEDULER_add_at (req->expires,
1025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026 "Throttling for 1ms\n");
1028 GNUNET_SCHEDULER_cancel (t);
1029 t = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
1037 * Clean up and terminate the process.
1042 do_shutdown (void *cls)
1044 struct Request *req;
1050 GNUNET_IDENTITY_disconnect (id);
1055 GNUNET_SCHEDULER_cancel (t);
1058 while (NULL != (req = req_head))
1060 GNUNET_CONTAINER_DLL_remove (req_head,
1063 if (NULL != req->qe)
1064 GNUNET_NAMESTORE_cancel (req->qe);
1067 while (NULL != (req = GNUNET_CONTAINER_heap_remove_root (req_heap)))
1070 if (NULL != req->qe)
1071 GNUNET_NAMESTORE_cancel (req->qe);
1076 GNUNET_NAMESTORE_disconnect (ns);
1081 GNUNET_DNSSTUB_stop (ctx);
1084 if (NULL != req_heap)
1086 GNUNET_CONTAINER_heap_destroy (req_heap);
1089 while (NULL != (zone = zone_head))
1091 GNUNET_CONTAINER_DLL_remove (zone_head,
1094 GNUNET_free (zone->domain);
1101 * Begin processing hostnames from stdin.
1106 process_stdin (void *cls);
1110 * If applicable, continue processing from stdin.
1115 if ( (pending < THRESH) &&
1119 GNUNET_SCHEDULER_cancel (t);
1120 t = GNUNET_SCHEDULER_add_now (&process_stdin,
1127 * Function called if #GNUNET_NAMESTORE_records_lookup() failed.
1128 * Continues resolution based on assumption namestore has no data.
1130 * @param cls a `struct Request`
1133 ns_lookup_error_cb (void *cls)
1135 struct Request *req = cls;
1138 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1139 "Failed to load data from namestore for `%s'\n",
1141 insert_sorted (req);
1148 * Process a record that was stored in the namestore.
1150 * @param cls a `struct Request *`
1151 * @param zone private key of the zone
1152 * @param label label of the records
1153 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1154 * @param rd array of records with data to store
1157 ns_lookup_result_cb (void *cls,
1158 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1160 unsigned int rd_count,
1161 const struct GNUNET_GNSRECORD_Data *rd)
1163 struct Request *req = cls;
1167 GNUNET_break (0 == memcmp (zone,
1170 GNUNET_break (0 == strcasecmp (label,
1172 for (unsigned int i=0;i<rd_count;i++)
1174 struct GNUNET_TIME_Absolute at;
1176 at.abs_value_us = rd->expiration_time;
1185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1186 "Empty record set in namestore for `%s'\n",
1191 unsigned int pos = 0;
1193 req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
1194 for (struct Record *rec = req->rec_head;
1198 struct GNUNET_TIME_Absolute at;
1200 at.abs_value_us = rec->grd.expiration_time;
1201 req->expires = GNUNET_TIME_absolute_min (req->expires,
1206 req->expires = GNUNET_TIME_UNIT_ZERO_ABS;
1207 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1208 "Hot-start with %u existing records for `%s'\n",
1212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1213 "Adding `%s' to worklist to start at %s\n",
1215 GNUNET_STRINGS_absolute_time_to_string (req->expires));
1216 insert_sorted (req);
1222 * Add @a hostname to the list of requests to be made.
1224 * @param hostname name to resolve
1227 queue (const char *hostname)
1229 struct GNUNET_DNSPARSER_Packet p;
1230 struct GNUNET_DNSPARSER_Query q;
1231 struct Request *req;
1238 GNUNET_DNSPARSER_check_name (hostname))
1240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1241 "Refusing invalid hostname `%s'\n",
1247 dot = strchr (hostname,
1248 (unsigned char) '.');
1251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1252 "Refusing invalid hostname `%s' (lacks '.')\n",
1258 for (zone = zone_head; NULL != zone; zone = zone->next)
1259 if (0 == strcmp (zone->domain,
1265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1266 "Domain name `%s' not in ego list!\n",
1271 q.name = (char *) hostname;
1272 q.type = GNUNET_DNSPARSER_TYPE_NS;
1273 q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1280 p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1284 GNUNET_DNSPARSER_pack (&p,
1289 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1290 "Failed to pack query for hostname `%s'\n",
1298 req = GNUNET_new (struct Request);
1300 req->hostname = GNUNET_strdup (hostname);
1302 req->raw_len = raw_size;
1304 req->label = GNUNET_strndup (hostname,
1306 req->qe = GNUNET_NAMESTORE_records_lookup (ns,
1309 &ns_lookup_error_cb,
1311 &ns_lookup_result_cb,
1317 * Begin processing hostnames from stdin.
1322 process_stdin (void *cls)
1324 static unsigned int pdot;
1331 GNUNET_IDENTITY_disconnect (id);
1340 hn[strlen(hn)-1] = '\0'; /* eat newline */
1342 if (0 == pdot % 1000)
1343 fprintf (stderr, ".");
1347 stdin_waiting = GNUNET_NO;
1348 fprintf (stderr, "\n");
1349 t = GNUNET_SCHEDULER_add_now (&process_queue,
1355 * Method called to inform about the egos of this peer.
1357 * When used with #GNUNET_IDENTITY_connect, this function is
1358 * initially called for all egos and then again whenever a
1359 * ego's name changes or if it is deleted. At the end of
1360 * the initial pass over all egos, the function is once called
1361 * with 'NULL' for @a ego. That does NOT mean that the callback won't
1362 * be invoked in the future or that there was an error.
1364 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
1365 * this function is only called ONCE, and 'NULL' being passed in
1366 * @a ego does indicate an error (i.e. name is taken or no default
1367 * value is known). If @a ego is non-NULL and if '*ctx'
1368 * is set in those callbacks, the value WILL be passed to a subsequent
1369 * call to the identity callback of #GNUNET_IDENTITY_connect (if
1370 * that one was not NULL).
1372 * When an identity is renamed, this function is called with the
1373 * (known) @a ego but the NEW @a name.
1375 * When an identity is deleted, this function is called with the
1376 * (known) ego and "NULL" for the @a name. In this case,
1377 * the @a ego is henceforth invalid (and the @a ctx should also be
1380 * @param cls closure
1381 * @param ego ego handle
1382 * @param ctx context for application to store data for this ego
1383 * (during the lifetime of this process, initially NULL)
1384 * @param name name assigned by the user for this ego,
1385 * NULL if the user just deleted the ego and it
1386 * must thus no longer be used
1389 identity_cb (void *cls,
1390 struct GNUNET_IDENTITY_Ego *ego,
1398 if (NULL != zone_head)
1400 stdin_waiting = GNUNET_YES;
1401 t = GNUNET_SCHEDULER_add_now (&process_stdin,
1406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407 "Specified zone not found\n");
1408 GNUNET_SCHEDULER_shutdown ();
1416 zone = GNUNET_new (struct Zone);
1417 zone->key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1418 zone->domain = GNUNET_strdup (name);
1419 GNUNET_CONTAINER_DLL_insert (zone_head,
1427 * Process requests from the queue, then if the queue is
1428 * not empty, try again.
1431 * @param args remaining command-line arguments
1432 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1433 * @param cfg configuration
1438 const char *cfgfile,
1439 const struct GNUNET_CONFIGURATION_Handle *cfg)
1444 req_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1445 ctx = GNUNET_DNSSTUB_start (256);
1449 "Failed to initialize GNUnet DNS STUB\n");
1452 if (NULL == args[0])
1455 "You must provide a list of DNS resolvers on the command line\n");
1458 for (unsigned int i=0;NULL != args[i];i++)
1461 GNUNET_DNSSTUB_add_dns_ip (ctx,
1465 "Failed to use `%s' for DNS resolver\n",
1472 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1474 ns = GNUNET_NAMESTORE_connect (cfg);
1477 GNUNET_SCHEDULER_shutdown ();
1480 id = GNUNET_IDENTITY_connect (cfg,
1487 * Call with IP address of resolver to query.
1489 * @param argc should be 2
1490 * @param argv[1] should contain IP address
1491 * @return 0 on success
1497 struct GNUNET_GETOPT_CommandLineOption options[] = {
1498 GNUNET_GETOPT_OPTION_END
1502 GNUNET_STRINGS_get_utf8_args (argc, argv,
1505 GNUNET_PROGRAM_run (argc,
1507 "gnunet-zoneimport",
1508 "import DNS zone into namestore",
1512 GNUNET_free ((void*) argv);
1514 "Rejected %u names, did %u lookups, found %u records, %u lookups failed, %u pending on shutdown\n",
1523 /* end of gnunet-zoneimport.c */