gnunet-service-gns_shorten.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2011-2013 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file gns/gnunet-service-gns_shorten.c
  19. * @brief GNUnet GNS shortening logic
  20. * @author Martin Schanzenbach
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_dht_service.h"
  26. #include "gnunet_gnsrecord_lib.h"
  27. #include "gnunet_namestore_service.h"
  28. #include "gnunet_resolver_service.h"
  29. #include "gnunet_gns_service.h"
  30. #include "gns.h"
  31. #include "gnunet-service-gns_shorten.h"
  32. #include "gnunet_vpn_service.h"
  33. /**
  34. * Default DHT timeout for lookups.
  35. */
  36. #define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
  37. /**
  38. * DHT replication level
  39. */
  40. #define DHT_GNS_REPLICATION_LEVEL 5
  41. /**
  42. * Handle for a PSEU lookup used to shorten names.
  43. */
  44. struct GetPseuAuthorityHandle
  45. {
  46. /**
  47. * DLL
  48. */
  49. struct GetPseuAuthorityHandle *next;
  50. /**
  51. * DLL
  52. */
  53. struct GetPseuAuthorityHandle *prev;
  54. /**
  55. * Private key of the (shorten) zone to store the resulting
  56. * pseudonym in.
  57. */
  58. struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_zone_key;
  59. /**
  60. * Original label (used if no PSEU record is found).
  61. */
  62. char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
  63. /**
  64. * Suggested label based on NICK record
  65. */
  66. char * suggested_label;
  67. /**
  68. * Label we are currently trying out
  69. */
  70. char *current_label;
  71. /**
  72. * The zone for which we are trying to find the PSEU record.
  73. */
  74. struct GNUNET_CRYPTO_EcdsaPublicKey target_zone;
  75. /**
  76. * Handle for DHT lookups. Should be NULL if no lookups are in progress
  77. */
  78. struct GNUNET_DHT_GetHandle *get_handle;
  79. /**
  80. * Handle to namestore request
  81. */
  82. struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
  83. /**
  84. * Handle to namecache request
  85. */
  86. struct GNUNET_NAMECACHE_QueueEntry *namecache_task;
  87. /**
  88. * Task to abort DHT lookup operation.
  89. */
  90. GNUNET_SCHEDULER_TaskIdentifier timeout_task;
  91. };
  92. /**
  93. * Head of PSEU/shorten operations list.
  94. */
  95. static struct GetPseuAuthorityHandle *gph_head;
  96. /**
  97. * Tail of PSEU/shorten operations list.
  98. */
  99. static struct GetPseuAuthorityHandle *gph_tail;
  100. /**
  101. * Our handle to the namestore service
  102. */
  103. static struct GNUNET_NAMESTORE_Handle *namestore_handle;
  104. /**
  105. * Our handle to the namecache service
  106. */
  107. static struct GNUNET_NAMECACHE_Handle *namecache_handle;
  108. /**
  109. * Resolver handle to the dht
  110. */
  111. static struct GNUNET_DHT_Handle *dht_handle;
  112. /**
  113. * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
  114. * pending activities.
  115. *
  116. * @param gph handle to terminate
  117. */
  118. static void
  119. free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
  120. {
  121. if (NULL != gph->get_handle)
  122. {
  123. GNUNET_DHT_get_stop (gph->get_handle);
  124. gph->get_handle = NULL;
  125. }
  126. if (NULL != gph->namestore_task)
  127. {
  128. GNUNET_NAMESTORE_cancel (gph->namestore_task);
  129. gph->namestore_task = NULL;
  130. }
  131. if (NULL != gph->namecache_task)
  132. {
  133. GNUNET_NAMECACHE_cancel (gph->namecache_task);
  134. gph->namecache_task = NULL;
  135. }
  136. if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
  137. {
  138. GNUNET_SCHEDULER_cancel (gph->timeout_task);
  139. gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  140. }
  141. GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
  142. GNUNET_free_non_null (gph->current_label);
  143. GNUNET_free (gph);
  144. }
  145. /**
  146. * Continuation for pkey record creation (shorten)
  147. *
  148. * @param cls a GetPseuAuthorityHandle
  149. * @param success unused
  150. * @param emsg unused
  151. */
  152. static void
  153. create_pkey_cont (void* cls,
  154. int32_t success,
  155. const char *emsg)
  156. {
  157. struct GetPseuAuthorityHandle* gph = cls;
  158. gph->namestore_task = NULL;
  159. free_get_pseu_authority_handle (gph);
  160. }
  161. /**
  162. * Namestore calls this function if we have record for this name.
  163. * (or with rd_count=0 to indicate no matches).
  164. *
  165. * @param cls the pending query
  166. * @param rd_count the number of records with 'name'
  167. * @param rd the record data
  168. */
  169. static void
  170. process_pseu_lookup_ns (void *cls,
  171. unsigned int rd_count,
  172. const struct GNUNET_GNSRECORD_Data *rd);
  173. /**
  174. * We obtained a result for our query to the shorten zone from
  175. * the namestore. Try to decrypt.
  176. *
  177. * @param cls the handle to our shorten operation
  178. * @param block resulting encrypted block
  179. */
  180. static void
  181. process_pseu_block_ns (void *cls,
  182. const struct GNUNET_GNSRECORD_Block *block)
  183. {
  184. struct GetPseuAuthorityHandle *gph = cls;
  185. struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  186. gph->namecache_task = NULL;
  187. if (NULL == block)
  188. {
  189. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  190. "Namecache did not return information for label `%s' \n",
  191. gph->current_label);
  192. process_pseu_lookup_ns (gph, 0, NULL);
  193. return;
  194. }
  195. GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
  196. &pub);
  197. if (GNUNET_OK !=
  198. GNUNET_GNSRECORD_block_decrypt (block,
  199. &pub,
  200. gph->current_label,
  201. &process_pseu_lookup_ns,
  202. gph))
  203. {
  204. GNUNET_break (0);
  205. free_get_pseu_authority_handle (gph);
  206. return;
  207. }
  208. }
  209. /**
  210. * Lookup in the namecache for the shorten zone the given label.
  211. *
  212. * @param gph the handle to our shorten operation
  213. * @param label the label to lookup
  214. */
  215. static void
  216. perform_nick_lookup (struct GetPseuAuthorityHandle *gph,
  217. const char *label)
  218. {
  219. struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  220. struct GNUNET_HashCode query;
  221. GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
  222. &pub);
  223. GNUNET_free_non_null (gph->current_label);
  224. gph->current_label = GNUNET_strdup (label);
  225. GNUNET_GNSRECORD_query_from_public_key (&pub,
  226. label,
  227. &query);
  228. gph->namecache_task = GNUNET_NAMECACHE_lookup_block (namecache_handle,
  229. &query,
  230. &process_pseu_block_ns,
  231. gph);
  232. }
  233. /**
  234. * Namestore calls this function if we have record for this name.
  235. * (or with rd_count=0 to indicate no matches).
  236. *
  237. * @param cls the pending query
  238. * @param rd_count the number of records with 'name'
  239. * @param rd the record data
  240. */
  241. static void
  242. process_pseu_lookup_ns (void *cls,
  243. unsigned int rd_count,
  244. const struct GNUNET_GNSRECORD_Data *rd)
  245. {
  246. struct GetPseuAuthorityHandle *gph = cls;
  247. struct GNUNET_GNSRECORD_Data new_pkey;
  248. gph->namestore_task = NULL;
  249. if (rd_count > 0)
  250. {
  251. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  252. "Name `%s' already taken, cannot shorten.\n",
  253. gph->current_label);
  254. /* if this was not yet the original label, try one more
  255. time, this time not using PSEU but the original label */
  256. if (0 == strcmp (gph->current_label,
  257. gph->label))
  258. {
  259. free_get_pseu_authority_handle (gph);
  260. }
  261. else
  262. {
  263. perform_nick_lookup (gph, gph->label);
  264. }
  265. return;
  266. }
  267. /* name is available */
  268. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  269. "Shortening `%s' to `%s'\n",
  270. GNUNET_GNSRECORD_z2s (&gph->target_zone),
  271. gph->current_label);
  272. new_pkey.expiration_time = UINT64_MAX;
  273. new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
  274. new_pkey.data = &gph->target_zone;
  275. new_pkey.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
  276. new_pkey.flags = GNUNET_GNSRECORD_RF_NONE
  277. | GNUNET_GNSRECORD_RF_PRIVATE;
  278. gph->namestore_task
  279. = GNUNET_NAMESTORE_records_store (namestore_handle,
  280. &gph->shorten_zone_key,
  281. gph->current_label,
  282. 1, &new_pkey,
  283. &create_pkey_cont, gph);
  284. }
  285. /**
  286. * Callback called by namestore for a zone to name result. We're
  287. * trying to see if a short name for a given zone already exists.
  288. *
  289. * @param cls the closure
  290. * @param zone_key the zone we queried
  291. * @param name the name found or NULL
  292. * @param rd_len number of records for the name
  293. * @param rd the record data (PKEY) for the name
  294. */
  295. static void
  296. process_zone_to_name_discover (void *cls,
  297. const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
  298. const char *name,
  299. unsigned int rd_len,
  300. const struct GNUNET_GNSRECORD_Data *rd)
  301. {
  302. struct GetPseuAuthorityHandle* gph = cls;
  303. #if 0
  304. struct GNUNET_HashCode lookup_key;
  305. #endif
  306. gph->namestore_task = NULL;
  307. if (0 != rd_len)
  308. {
  309. /* we found a match in our own zone */
  310. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  311. "Shortening aborted, name `%s' already reserved for the zone\n",
  312. name);
  313. free_get_pseu_authority_handle (gph);
  314. return;
  315. }
  316. else
  317. {
  318. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  319. "Shortening continuing, no name not reserved in shorten zone\n");
  320. }
  321. /* record does not yet exist, check if suggested label is available */
  322. perform_nick_lookup (gph, gph->suggested_label);
  323. }
  324. /**
  325. * Start shortening algorithm, try to allocate a nice short
  326. * canonical name for @a pub in @a shorten_zone, using
  327. * @a original_label as one possible suggestion.
  328. *
  329. * @param original_label original label for the zone
  330. * @param suggested_label suggested label for the zone
  331. * @param pub public key of the zone to shorten
  332. * @param shorten_zone private key of the target zone for the new record
  333. */
  334. void
  335. GNS_shorten_start (const char *original_label,
  336. const char *suggested_label,
  337. const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
  338. const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone)
  339. {
  340. struct GetPseuAuthorityHandle *gph;
  341. struct GNUNET_CRYPTO_EcdsaPublicKey shorten_pub;
  342. if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
  343. {
  344. GNUNET_break (0);
  345. return;
  346. }
  347. GNUNET_CRYPTO_ecdsa_key_get_public (shorten_zone, &shorten_pub);
  348. if (0 == memcmp (&shorten_pub, pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
  349. {
  350. /* Do not shorten the shorten zone */
  351. return;
  352. }
  353. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  354. "Starting shortening process for `%s' with old label `%s' and suggested nickname `%s'\n",
  355. GNUNET_GNSRECORD_z2s (pub),
  356. original_label, suggested_label);
  357. gph = GNUNET_new (struct GetPseuAuthorityHandle);
  358. gph->shorten_zone_key = *shorten_zone;
  359. gph->target_zone = *pub;
  360. gph->suggested_label = GNUNET_strdup (suggested_label);
  361. strcpy (gph->label, original_label);
  362. GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
  363. /* first, check if we *already* have a record for this zone */
  364. gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
  365. shorten_zone,
  366. pub,
  367. &process_zone_to_name_discover,
  368. gph);
  369. }
  370. /**
  371. * Initialize the shortening subsystem
  372. *
  373. * @param nh the namestore handle
  374. * @param nc the namecache handle
  375. * @param dht the dht handle
  376. */
  377. void
  378. GNS_shorten_init (struct GNUNET_NAMESTORE_Handle *nh,
  379. struct GNUNET_NAMECACHE_Handle *nc,
  380. struct GNUNET_DHT_Handle *dht)
  381. {
  382. namestore_handle = nh;
  383. namecache_handle = nc;
  384. dht_handle = dht;
  385. }
  386. /**
  387. * Shutdown shortening.
  388. */
  389. void
  390. GNS_shorten_done ()
  391. {
  392. /* abort active shorten operations */
  393. while (NULL != gph_head)
  394. free_get_pseu_authority_handle (gph_head);
  395. dht_handle = NULL;
  396. namestore_handle = NULL;
  397. namecache_handle = NULL;
  398. }
  399. /* end of gnunet-service-gns_shorten.c */