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