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