add possibility of hijacking any (sub)domain, not just TLDs, via configuration file...
[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 const 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 tld;
107 }
108
109
110 /**
111  * Eat the "TLD" (last bit) of the given @a name.
112  *
113  * @param[in,out] name a name
114  * @param tld what to eat (can be more than just the tld)
115  */
116 static void
117 eat_tld (char *name,
118          const char *tld)
119 {
120   GNUNET_assert (0 < strlen (name));
121   if (NULL == tld)
122   {
123     strcpy (name,
124             GNUNET_GNS_EMPTY_LABEL_AT);
125   }
126   else
127   {
128     GNUNET_assert (strlen (tld) < strlen (name));
129     name[strlen(name) - strlen(tld) - 1] = '\0';
130   }
131 }
132
133
134 /**
135  * Function called with the result of a GNS lookup.
136  *
137  * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
138  * @param rd_count number of records returned
139  * @param rd array of @a rd_count records with the results
140  */
141 static void
142 process_lookup_result (void *cls,
143                        uint32_t rd_count,
144                        const struct GNUNET_GNSRECORD_Data *rd)
145 {
146   struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
147
148   ltr->lr = NULL;
149   ltr->lookup_proc (ltr->lookup_proc_cls,
150                     GNUNET_YES,
151                     rd_count,
152                     rd);
153   GNUNET_GNS_lookup_with_tld_cancel (ltr);
154 }
155
156
157 /**
158  * Perform the actual resolution, starting with the zone
159  * identified by the given public key.
160  *
161  * @param pkey public key to use for the zone, can be NULL
162  */
163 static void
164 lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
165                         const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
166 {
167   ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
168                                ltr->name,
169                                pkey,
170                                ltr->type,
171                                ltr->options,
172                                &process_lookup_result,
173                                ltr);
174 }
175
176
177 /**
178  * Method called to with the ego we are to use for the lookup,
179  * when the ego is determined by a name.
180  *
181  * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
182  * @param ego ego handle, NULL if not found
183  */
184 static void
185 identity_zone_cb (void *cls,
186                   const struct GNUNET_IDENTITY_Ego *ego)
187 {
188   struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
189   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
190
191   ltr->id_op = NULL;
192   if (NULL == ego)
193   {
194     ltr->lookup_proc (ltr->lookup_proc_cls,
195                       GNUNET_NO,
196                       0,
197                       NULL);
198     GNUNET_GNS_lookup_with_tld_cancel (ltr);
199     return;
200   }
201   else
202   {
203     GNUNET_IDENTITY_ego_get_public_key (ego,
204                                         &pkey);
205     lookup_with_public_key (ltr,
206                             &pkey);
207   }
208 }
209
210
211 /**
212  * Perform an asynchronous lookup operation on the GNS,
213  * determining the zone using the TLD of the given name
214  * and the current configuration to resolve TLDs to zones.
215  *
216  * @param handle handle to the GNS service
217  * @param name the name to look up, including TLD
218  * @param type the record type to look up
219  * @param options local options for the lookup
220  * @param proc processor to call on result
221  * @param proc_cls closure for @a proc
222  * @return handle to the get request, NULL on error (i.e. bad configuration)
223  */
224 struct GNUNET_GNS_LookupWithTldRequest *
225 GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
226                             const char *name,
227                             uint32_t type,
228                             enum GNUNET_GNS_LocalOptions options,
229                             GNUNET_GNS_LookupResultProcessor2 proc,
230                             void *proc_cls)
231 {
232   struct GNUNET_GNS_LookupWithTldRequest *ltr;
233   const char *tld;
234   char *dot_tld;
235   char *zonestr;
236   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
237
238   ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
239   ltr->gns_handle = handle;
240   ltr->name = GNUNET_strdup (name);
241   ltr->type = type;
242   ltr->options = options;
243   ltr->lookup_proc = proc;
244   ltr->lookup_proc_cls = proc_cls;
245   /* start with trivial case: TLD is zkey */
246   tld = get_tld (ltr->name);
247   if (GNUNET_OK ==
248       GNUNET_CRYPTO_ecdsa_public_key_from_string (tld,
249                                                   strlen (tld),
250                                                   &pkey))
251   {
252     eat_tld (ltr->name,
253              tld);
254     lookup_with_public_key (ltr,
255                             &pkey);
256     return ltr;
257   }
258
259   /* second case: domain is mapped in our configuration file */
260   for (const char *domain = name;
261        NULL != domain;
262        domain = strchr (domain,
263                         (unsigned char) '.'))
264   {
265     if ('.' == domain[0])
266       domain++;
267     GNUNET_asprintf (&dot_tld,
268                      ".%s",
269                      domain);
270     if (GNUNET_OK ==
271         GNUNET_CONFIGURATION_get_value_string (handle->cfg,
272                                                "gns",
273                                                dot_tld,
274                                                &zonestr))
275     {
276       if (GNUNET_OK !=
277           GNUNET_CRYPTO_ecdsa_public_key_from_string (zonestr,
278                                                       strlen (zonestr),
279                                                       &pkey))
280       {
281         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
282                                    "gns",
283                                    dot_tld,
284                                    _("Expected a base32-encoded public zone key\n"));
285         GNUNET_free (zonestr);
286         GNUNET_free (dot_tld);
287         GNUNET_free (ltr->name);
288         GNUNET_free (ltr);
289         return NULL;
290       }
291       eat_tld (ltr->name,
292                &dot_tld[1]);
293       GNUNET_free (zonestr);
294       GNUNET_free (dot_tld);
295       lookup_with_public_key (ltr,
296                               &pkey);
297       return ltr;
298     }
299     GNUNET_free (dot_tld);
300   }
301
302   /* Final case: TLD matches one of our egos */
303   eat_tld (ltr->name,
304            tld);
305
306   /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
307   if (NULL == strchr (ltr->name,
308                       (unsigned char) '.'))
309     ltr->options = GNUNET_GNS_LO_NO_DHT;
310   else
311     ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
312   ltr->id_op = GNUNET_IDENTITY_ego_lookup (ltr->gns_handle->cfg,
313                                            tld,
314                                            &identity_zone_cb,
315                                            ltr);
316   if (NULL == ltr->id_op)
317   {
318     GNUNET_free (ltr->name);
319     GNUNET_free (ltr);
320     return NULL;
321   }
322   return ltr;
323 }
324
325
326 /**
327  * Cancel pending lookup request
328  *
329  * @param ltr the lookup request to cancel
330  * @return closure from the lookup result processor
331  */
332 void *
333 GNUNET_GNS_lookup_with_tld_cancel (struct GNUNET_GNS_LookupWithTldRequest *ltr)
334 {
335   void *ret = ltr->lookup_proc_cls;
336   
337   if (NULL != ltr->id_op)
338   {
339     GNUNET_IDENTITY_ego_lookup_cancel (ltr->id_op);
340     ltr->id_op = NULL;
341   }
342   if (NULL != ltr->lr)
343   {
344     GNUNET_GNS_lookup_cancel (ltr->lr);
345     ltr->lr = NULL;
346   }
347   GNUNET_free (ltr->name);
348   GNUNET_free (ltr);
349   return ret;
350 }
351
352 /* end of gns_tld_api.c */