gns_tld_api.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-2013, 2016, 2018 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your 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. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file gns/gns_tld_api.c
  18. * @brief library to access the GNS service, including TLD lookup
  19. * @author Martin Schanzenbach
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_arm_service.h"
  26. #include "gnunet_identity_service.h"
  27. #include "gnunet_hello_lib.h"
  28. #include "gnunet_protocols.h"
  29. #include "gnunet_dht_service.h"
  30. #include "gns.h"
  31. #include "gns_api.h"
  32. #define LOG(kind, ...) GNUNET_log_from (kind, "gns-tld-api", __VA_ARGS__)
  33. /**
  34. * Handle to a lookup request
  35. */
  36. struct GNUNET_GNS_LookupWithTldRequest
  37. {
  38. /**
  39. * handle to gns
  40. */
  41. struct GNUNET_GNS_Handle *gns_handle;
  42. /**
  43. * processor to call on lookup result
  44. */
  45. GNUNET_GNS_LookupResultProcessor2 lookup_proc;
  46. /**
  47. * Domain name we are resolving.
  48. */
  49. char *name;
  50. /**
  51. * @e lookup_proc closure
  52. */
  53. void *lookup_proc_cls;
  54. /**
  55. * Underlying GNS lookup.
  56. */
  57. struct GNUNET_GNS_LookupRequest *lr;
  58. /**
  59. * Lookup an ego with the identity service.
  60. */
  61. struct GNUNET_IDENTITY_EgoSuffixLookup *id_co;
  62. /**
  63. * Name of the longest matching ego found so far.
  64. * Must be freed on termination.
  65. */
  66. char *longest_match;
  67. /**
  68. * Ego corresponding to @e longest_match.
  69. */
  70. struct GNUNET_IDENTITY_Ego *longest_match_ego;
  71. /**
  72. * Desired result record type.
  73. */
  74. uint32_t type;
  75. /**
  76. * Lookup options.
  77. */
  78. enum GNUNET_GNS_LocalOptions options;
  79. };
  80. /**
  81. * Obtain the TLD of the given @a name.
  82. *
  83. * @param name a name
  84. * @return the part of @a name after the last ".",
  85. * or @a name if @a name does not contain a "."
  86. */
  87. static const char *
  88. get_tld (const char *name)
  89. {
  90. const char *tld;
  91. tld = strrchr (name, (unsigned char) '.');
  92. if (NULL == tld)
  93. tld = name;
  94. else
  95. tld++; /* skip the '.' */
  96. return tld;
  97. }
  98. /**
  99. * Eat the "TLD" (last bit) of the given @a name.
  100. *
  101. * @param[in,out] name a name
  102. * @param tld what to eat (can be more than just the tld)
  103. */
  104. static void
  105. eat_tld (char *name, const char *tld)
  106. {
  107. GNUNET_assert (0 < strlen (name));
  108. if ((NULL == tld) || (strlen (name) == strlen (tld)))
  109. {
  110. strcpy (name, GNUNET_GNS_EMPTY_LABEL_AT);
  111. }
  112. else
  113. {
  114. GNUNET_assert (strlen (tld) < strlen (name));
  115. name[strlen (name) - strlen (tld) - 1] = '\0';
  116. }
  117. }
  118. /**
  119. * Function called with the result of a GNS lookup.
  120. *
  121. * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
  122. * @param rd_count number of records returned
  123. * @param rd array of @a rd_count records with the results
  124. */
  125. static void
  126. process_lookup_result (void *cls,
  127. uint32_t rd_count,
  128. const struct GNUNET_GNSRECORD_Data *rd)
  129. {
  130. struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
  131. ltr->lr = NULL;
  132. ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_YES, rd_count, rd);
  133. GNUNET_GNS_lookup_with_tld_cancel (ltr);
  134. }
  135. /**
  136. * Perform the actual resolution, starting with the zone
  137. * identified by the given public key.
  138. *
  139. * @param pkey public key to use for the zone, can be NULL
  140. */
  141. static void
  142. lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
  143. const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
  144. {
  145. ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
  146. ltr->name,
  147. pkey,
  148. ltr->type,
  149. ltr->options,
  150. &process_lookup_result,
  151. ltr);
  152. }
  153. /**
  154. * Method called to with the ego we are to use for the lookup,
  155. * when the ego is determined by a name.
  156. *
  157. * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
  158. * @param ego ego handle, NULL at the end of the iteration
  159. * @param ctx context we could store data to associate with @e ego
  160. * @param name name of the ego
  161. */
  162. static void
  163. identity_zone_cb (void *cls,
  164. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
  165. const char *ego_name)
  166. {
  167. struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
  168. struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  169. ltr->id_co = NULL;
  170. if (NULL == priv)
  171. {
  172. /* no matching ego found */
  173. ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_NO, 0, NULL);
  174. return;
  175. }
  176. /* Final case: TLD matches one of our egos */
  177. if (0 == strcmp (ltr->name, ego_name))
  178. {
  179. /* name matches ego name perfectly, only "@" remains */
  180. strcpy (ltr->name, GNUNET_GNS_EMPTY_LABEL_AT);
  181. }
  182. else
  183. {
  184. GNUNET_assert (strlen (ego_name) < strlen (ltr->name));
  185. ltr->name[strlen (ltr->name) - strlen (ego_name) - 1] = '\0';
  186. }
  187. /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
  188. if (NULL == strchr (ltr->name, (unsigned char) '.'))
  189. ltr->options = GNUNET_GNS_LO_NO_DHT;
  190. else
  191. ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
  192. GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pkey);
  193. lookup_with_public_key (ltr, &pkey);
  194. }
  195. /**
  196. * Perform an asynchronous lookup operation on the GNS,
  197. * determining the zone using the TLD of the given name
  198. * and the current configuration to resolve TLDs to zones.
  199. *
  200. * @param handle handle to the GNS service
  201. * @param name the name to look up, including TLD (in UTF-8 encoding)
  202. * @param type the record type to look up
  203. * @param options local options for the lookup
  204. * @param proc processor to call on result
  205. * @param proc_cls closure for @a proc
  206. * @return handle to the get request, NULL on error (i.e. bad configuration)
  207. */
  208. struct GNUNET_GNS_LookupWithTldRequest *
  209. GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
  210. const char *name,
  211. uint32_t type,
  212. enum GNUNET_GNS_LocalOptions options,
  213. GNUNET_GNS_LookupResultProcessor2 proc,
  214. void *proc_cls)
  215. {
  216. struct GNUNET_GNS_LookupWithTldRequest *ltr;
  217. const char *tld;
  218. char *dot_tld;
  219. char *zonestr;
  220. struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  221. ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
  222. ltr->gns_handle = handle;
  223. ltr->name = GNUNET_strdup (name);
  224. ltr->type = type;
  225. ltr->options = options;
  226. ltr->lookup_proc = proc;
  227. ltr->lookup_proc_cls = proc_cls;
  228. /* start with trivial case: TLD is zkey */
  229. tld = get_tld (ltr->name);
  230. if (GNUNET_OK ==
  231. GNUNET_CRYPTO_ecdsa_public_key_from_string (tld, strlen (tld), &pkey))
  232. {
  233. eat_tld (ltr->name, tld);
  234. lookup_with_public_key (ltr, &pkey);
  235. return ltr;
  236. }
  237. /* second case: domain is mapped in our configuration file */
  238. for (const char *domain = name; NULL != domain;
  239. domain = strchr (domain, (unsigned char) '.'))
  240. {
  241. if ('.' == domain[0])
  242. domain++;
  243. GNUNET_asprintf (&dot_tld, ".%s", domain);
  244. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (handle->cfg,
  245. "gns",
  246. dot_tld,
  247. &zonestr))
  248. {
  249. if (GNUNET_OK !=
  250. GNUNET_CRYPTO_ecdsa_public_key_from_string (zonestr,
  251. strlen (zonestr),
  252. &pkey))
  253. {
  254. GNUNET_log_config_invalid (
  255. GNUNET_ERROR_TYPE_ERROR,
  256. "gns",
  257. dot_tld,
  258. _ ("Expected a base32-encoded public zone key\n"));
  259. GNUNET_free (zonestr);
  260. GNUNET_free (dot_tld);
  261. GNUNET_free (ltr->name);
  262. GNUNET_free (ltr);
  263. return NULL;
  264. }
  265. eat_tld (ltr->name, &dot_tld[1]);
  266. GNUNET_free (zonestr);
  267. GNUNET_free (dot_tld);
  268. lookup_with_public_key (ltr, &pkey);
  269. return ltr;
  270. }
  271. GNUNET_free (dot_tld);
  272. }
  273. ltr->id_co =
  274. GNUNET_IDENTITY_ego_lookup_by_suffix (ltr->gns_handle->cfg,
  275. ltr->name,
  276. &identity_zone_cb,
  277. ltr);
  278. if (NULL == ltr->id_co)
  279. {
  280. GNUNET_free (ltr->name);
  281. GNUNET_free (ltr);
  282. return NULL;
  283. }
  284. return ltr;
  285. }
  286. /**
  287. * Cancel pending lookup request
  288. *
  289. * @param ltr the lookup request to cancel
  290. * @return closure from the lookup result processor
  291. */
  292. void *
  293. GNUNET_GNS_lookup_with_tld_cancel (struct GNUNET_GNS_LookupWithTldRequest *ltr)
  294. {
  295. void *ret = ltr->lookup_proc_cls;
  296. if (NULL != ltr->id_co)
  297. {
  298. GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (ltr->id_co);
  299. ltr->id_co = NULL;
  300. }
  301. if (NULL != ltr->lr)
  302. {
  303. GNUNET_GNS_lookup_cancel (ltr->lr);
  304. ltr->lr = NULL;
  305. }
  306. GNUNET_free_non_null (ltr->longest_match);
  307. GNUNET_free (ltr->name);
  308. GNUNET_free (ltr);
  309. return ret;
  310. }
  311. /* end of gns_tld_api.c */