2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 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.
22 * @file gns/gnunet-service-gns_shorten.c
23 * @brief GNUnet GNS shortening logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dht_service.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_resolver_service.h"
33 #include "gnunet_gns_service.h"
35 #include "gnunet-service-gns_shorten.h"
36 #include "gnunet_vpn_service.h"
40 * Default DHT timeout for lookups.
42 #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
45 * DHT replication level
47 #define DHT_GNS_REPLICATION_LEVEL 5
51 * Handle for a PSEU lookup used to shorten names.
53 struct GetPseuAuthorityHandle
58 struct GetPseuAuthorityHandle *next;
63 struct GetPseuAuthorityHandle *prev;
66 * Private key of the (shorten) zone to store the resulting
69 struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_zone_key;
72 * Original label (used if no PSEU record is found).
74 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
77 * Suggested label based on NICK record
79 char * suggested_label;
82 * Label we are currently trying out
87 * The zone for which we are trying to find the PSEU record.
89 struct GNUNET_CRYPTO_EcdsaPublicKey target_zone;
92 * Handle for DHT lookups. Should be NULL if no lookups are in progress
94 struct GNUNET_DHT_GetHandle *get_handle;
97 * Handle to namestore request
99 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
102 * Handle to namecache request
104 struct GNUNET_NAMECACHE_QueueEntry *namecache_task;
107 * Task to abort DHT lookup operation.
109 struct GNUNET_SCHEDULER_Task * timeout_task;
115 * Head of PSEU/shorten operations list.
117 static struct GetPseuAuthorityHandle *gph_head;
120 * Tail of PSEU/shorten operations list.
122 static struct GetPseuAuthorityHandle *gph_tail;
125 * Our handle to the namestore service
127 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
130 * Our handle to the namecache service
132 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
135 * Resolver handle to the dht
137 static struct GNUNET_DHT_Handle *dht_handle;
140 * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
141 * pending activities.
143 * @param gph handle to terminate
146 free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
148 if (NULL != gph->get_handle)
150 GNUNET_DHT_get_stop (gph->get_handle);
151 gph->get_handle = NULL;
153 if (NULL != gph->namestore_task)
155 GNUNET_NAMESTORE_cancel (gph->namestore_task);
156 gph->namestore_task = NULL;
158 if (NULL != gph->namecache_task)
160 GNUNET_NAMECACHE_cancel (gph->namecache_task);
161 gph->namecache_task = NULL;
163 if (NULL != gph->timeout_task)
165 GNUNET_SCHEDULER_cancel (gph->timeout_task);
166 gph->timeout_task = NULL;
168 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
169 GNUNET_free_non_null (gph->current_label);
175 * Continuation for pkey record creation (shorten)
177 * @param cls a GetPseuAuthorityHandle
178 * @param success unused
182 create_pkey_cont (void* cls,
186 struct GetPseuAuthorityHandle* gph = cls;
188 gph->namestore_task = NULL;
189 free_get_pseu_authority_handle (gph);
194 * Namestore calls this function if we have record for this name.
195 * (or with rd_count=0 to indicate no matches).
197 * @param cls the pending query
198 * @param rd_count the number of records with 'name'
199 * @param rd the record data
202 process_pseu_lookup_ns (void *cls,
203 unsigned int rd_count,
204 const struct GNUNET_GNSRECORD_Data *rd);
208 * We obtained a result for our query to the shorten zone from
209 * the namestore. Try to decrypt.
211 * @param cls the handle to our shorten operation
212 * @param block resulting encrypted block
215 process_pseu_block_ns (void *cls,
216 const struct GNUNET_GNSRECORD_Block *block)
218 struct GetPseuAuthorityHandle *gph = cls;
219 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
221 gph->namecache_task = NULL;
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Namecache did not return information for label `%s' \n",
227 process_pseu_lookup_ns (gph, 0, NULL);
230 GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
233 GNUNET_GNSRECORD_block_decrypt (block,
236 &process_pseu_lookup_ns,
240 free_get_pseu_authority_handle (gph);
247 * Lookup in the namecache for the shorten zone the given label.
249 * @param gph the handle to our shorten operation
250 * @param label the label to lookup
253 perform_nick_lookup (struct GetPseuAuthorityHandle *gph,
256 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
257 struct GNUNET_HashCode query;
259 GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
261 GNUNET_free_non_null (gph->current_label);
262 gph->current_label = GNUNET_strdup (label);
263 GNUNET_GNSRECORD_query_from_public_key (&pub,
266 gph->namecache_task = GNUNET_NAMECACHE_lookup_block (namecache_handle,
268 &process_pseu_block_ns,
274 * Namestore calls this function if we have record for this name.
275 * (or with rd_count=0 to indicate no matches).
277 * @param cls the pending query
278 * @param rd_count the number of records with 'name'
279 * @param rd the record data
282 process_pseu_lookup_ns (void *cls,
283 unsigned int rd_count,
284 const struct GNUNET_GNSRECORD_Data *rd)
286 struct GetPseuAuthorityHandle *gph = cls;
287 struct GNUNET_GNSRECORD_Data new_pkey;
289 gph->namestore_task = NULL;
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293 "Name `%s' already taken, cannot shorten.\n",
295 /* if this was not yet the original label, try one more
296 time, this time not using PSEU but the original label */
297 if (0 == strcmp (gph->current_label,
300 free_get_pseu_authority_handle (gph);
304 perform_nick_lookup (gph, gph->label);
308 /* name is available */
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310 "Shortening `%s' to `%s'\n",
311 GNUNET_GNSRECORD_z2s (&gph->target_zone),
313 new_pkey.expiration_time = UINT64_MAX;
314 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
315 new_pkey.data = &gph->target_zone;
316 new_pkey.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
317 new_pkey.flags = GNUNET_GNSRECORD_RF_NONE
318 | GNUNET_GNSRECORD_RF_PRIVATE;
320 = GNUNET_NAMESTORE_records_store (namestore_handle,
321 &gph->shorten_zone_key,
324 &create_pkey_cont, gph);
329 * Encountered an error in zone-to-name lookup, give up on shortening.
332 zone_to_name_error_cb (void *cls)
334 struct GetPseuAuthorityHandle* gph = cls;
336 gph->namestore_task = NULL;
337 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
338 "Shortening aborted, internal error talking to namestore\n");
339 free_get_pseu_authority_handle (gph);
344 * Callback called by namestore for a zone to name result. We're
345 * trying to see if a short name for a given zone already exists.
347 * @param cls the closure
348 * @param zone_key the zone we queried
349 * @param name the name found or NULL
350 * @param rd_len number of records for the name
351 * @param rd the record data (PKEY) for the name
354 process_zone_to_name_discover (void *cls,
355 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
358 const struct GNUNET_GNSRECORD_Data *rd)
360 struct GetPseuAuthorityHandle* gph = cls;
362 gph->namestore_task = NULL;
365 /* we found a match in our own zone */
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "Shortening aborted, name `%s' already reserved for the zone\n",
369 free_get_pseu_authority_handle (gph);
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
375 "Shortening continuing, no name not reserved in shorten zone\n");
377 /* record does not yet exist, check if suggested label is available */
378 perform_nick_lookup (gph, gph->suggested_label);
383 * Start shortening algorithm, try to allocate a nice short
384 * canonical name for @a pub in @a shorten_zone, using
385 * @a original_label as one possible suggestion.
387 * @param original_label original label for the zone
388 * @param suggested_label suggested label for the zone
389 * @param pub public key of the zone to shorten
390 * @param shorten_zone private key of the target zone for the new record
393 GNS_shorten_start (const char *original_label,
394 const char *suggested_label,
395 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
396 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone)
398 struct GetPseuAuthorityHandle *gph;
399 struct GNUNET_CRYPTO_EcdsaPublicKey shorten_pub;
401 if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
406 GNUNET_CRYPTO_ecdsa_key_get_public (shorten_zone, &shorten_pub);
407 if (0 == memcmp (&shorten_pub, pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
409 /* Do not shorten the shorten zone */
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Starting shortening process for `%s' with old label `%s' and suggested nickname `%s'\n",
415 GNUNET_GNSRECORD_z2s (pub),
416 original_label, suggested_label);
417 gph = GNUNET_new (struct GetPseuAuthorityHandle);
418 gph->shorten_zone_key = *shorten_zone;
419 gph->target_zone = *pub;
420 gph->suggested_label = GNUNET_strdup (suggested_label);
421 strcpy (gph->label, original_label);
422 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
423 /* first, check if we *already* have a record for this zone */
424 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
427 &zone_to_name_error_cb,
429 &process_zone_to_name_discover,
435 * Initialize the shortening subsystem
437 * @param nh the namestore handle
438 * @param nc the namecache handle
439 * @param dht the dht handle
442 GNS_shorten_init (struct GNUNET_NAMESTORE_Handle *nh,
443 struct GNUNET_NAMECACHE_Handle *nc,
444 struct GNUNET_DHT_Handle *dht)
446 namestore_handle = nh;
447 namecache_handle = nc;
453 * Shutdown shortening.
458 /* abort active shorten operations */
459 while (NULL != gph_head)
460 free_get_pseu_authority_handle (gph_head);
462 namestore_handle = NULL;
463 namecache_handle = NULL;
466 /* end of gnunet-service-gns_shorten.c */