aboutsummaryrefslogtreecommitdiff
path: root/src/service/gns/gns_tld_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/gns/gns_tld_api.c')
-rw-r--r--src/service/gns/gns_tld_api.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/src/service/gns/gns_tld_api.c b/src/service/gns/gns_tld_api.c
new file mode 100644
index 000000000..1ea87fd97
--- /dev/null
+++ b/src/service/gns/gns_tld_api.c
@@ -0,0 +1,352 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
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_protocols.h"
32#include "gnunet_dht_service.h"
33#include "gns.h"
34#include "gns_api.h"
35
36
37#define LOG(kind, ...) GNUNET_log_from (kind, "gns-tld-api", __VA_ARGS__)
38
39
40/**
41 * Handle to a lookup request
42 */
43struct GNUNET_GNS_LookupWithTldRequest
44{
45 /**
46 * handle to gns
47 */
48 struct GNUNET_GNS_Handle *gns_handle;
49
50 /**
51 * processor to call on lookup result
52 */
53 GNUNET_GNS_LookupResultProcessor2 lookup_proc;
54
55 /**
56 * Domain name we are resolving.
57 */
58 char *name;
59
60 /**
61 * @e lookup_proc closure
62 */
63 void *lookup_proc_cls;
64
65 /**
66 * Underlying GNS lookup.
67 */
68 struct GNUNET_GNS_LookupRequest *lr;
69
70 /**
71 * Lookup an ego with the identity service.
72 */
73 struct GNUNET_IDENTITY_EgoSuffixLookup *id_co;
74
75 /**
76 * Name of the longest matching ego found so far.
77 * Must be freed on termination.
78 */
79 char *longest_match;
80
81 /**
82 * Ego corresponding to @e longest_match.
83 */
84 struct GNUNET_IDENTITY_Ego *longest_match_ego;
85
86 /**
87 * Desired result record type.
88 */
89 uint32_t type;
90
91 /**
92 * Lookup options.
93 */
94 enum GNUNET_GNS_LocalOptions options;
95};
96
97
98/**
99 * Obtain the TLD of the given @a name.
100 *
101 * @param name a name
102 * @return the part of @a name after the last ".",
103 * or @a name if @a name does not contain a "."
104 */
105static const char *
106get_tld (const char *name)
107{
108 const char *tld;
109
110 tld = strrchr (name, (unsigned char) '.');
111 if (NULL == tld)
112 tld = name;
113 else
114 tld++; /* skip the '.' */
115 return tld;
116}
117
118
119/**
120 * Eat the "TLD" (last bit) of the given @a name.
121 *
122 * @param[in,out] name a name
123 * @param tld what to eat (can be more than just the tld)
124 */
125static void
126eat_tld (char *name, const char *tld)
127{
128 GNUNET_assert (0 < strlen (name));
129 if ((NULL == tld) || (strlen (name) == strlen (tld)))
130 {
131 strcpy (name, GNUNET_GNS_EMPTY_LABEL_AT);
132 }
133 else
134 {
135 GNUNET_assert (strlen (tld) < strlen (name));
136 name[strlen (name) - strlen (tld) - 1] = '\0';
137 }
138}
139
140
141/**
142 * Function called with the result of a GNS lookup.
143 *
144 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
145 * @param rd_count number of records returned
146 * @param rd array of @a rd_count records with the results
147 */
148static void
149process_lookup_result (void *cls,
150 uint32_t rd_count,
151 const struct GNUNET_GNSRECORD_Data *rd)
152{
153 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
154
155 ltr->lr = NULL;
156 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_YES, rd_count, rd);
157 GNUNET_GNS_lookup_with_tld_cancel (ltr);
158}
159
160
161/**
162 * Perform the actual resolution, starting with the zone
163 * identified by the given public key.
164 *
165 * @param pkey public key to use for the zone, can be NULL
166 */
167static void
168lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
169 const struct GNUNET_CRYPTO_PublicKey *pkey)
170{
171 ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
172 ltr->name,
173 pkey,
174 ltr->type,
175 ltr->options,
176 &process_lookup_result,
177 ltr);
178}
179
180
181/**
182 * Method called to with the ego we are to use for the lookup,
183 * when the ego is determined by a name.
184 *
185 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
186 * @param ego ego handle, NULL at the end of the iteration
187 * @param ctx context we could store data to associate with @e ego
188 * @param ego_name name of the ego
189 */
190static void
191identity_zone_cb (void *cls,
192 const struct GNUNET_CRYPTO_PrivateKey *priv,
193 const char *ego_name)
194{
195 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
196 struct GNUNET_CRYPTO_PublicKey pkey;
197
198 ltr->id_co = NULL;
199 if (NULL == priv)
200 {
201 /* no matching ego found */
202 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_NO, 0, NULL);
203 return;
204 }
205 /* Final case: TLD matches one of our egos */
206 if (0 == strcmp (ltr->name, ego_name))
207 {
208 /* name matches ego name perfectly, only "@" remains */
209 strcpy (ltr->name, GNUNET_GNS_EMPTY_LABEL_AT);
210 }
211 else
212 {
213 GNUNET_assert (strlen (ego_name) < strlen (ltr->name));
214 ltr->name[strlen (ltr->name) - strlen (ego_name) - 1] = '\0';
215 }
216 /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
217 if (NULL == strchr (ltr->name, (unsigned char) '.'))
218 ltr->options = GNUNET_GNS_LO_NO_DHT;
219 else
220 ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
221 GNUNET_CRYPTO_key_get_public (priv, &pkey);
222 lookup_with_public_key (ltr, &pkey);
223}
224
225
226/**
227 * Perform an asynchronous lookup operation on the GNS,
228 * determining the zone using the TLD of the given name
229 * and the current configuration to resolve TLDs to zones.
230 *
231 * @param handle handle to the GNS service
232 * @param name the name to look up, including TLD (in UTF-8 encoding)
233 * @param type the record type to look up
234 * @param options local options for the lookup
235 * @param proc processor to call on result
236 * @param proc_cls closure for @a proc
237 * @return handle to the get request, NULL on error (e.g. bad configuration)
238 */
239struct GNUNET_GNS_LookupWithTldRequest *
240GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
241 const char *name,
242 uint32_t type,
243 enum GNUNET_GNS_LocalOptions options,
244 GNUNET_GNS_LookupResultProcessor2 proc,
245 void *proc_cls)
246{
247 struct GNUNET_GNS_LookupWithTldRequest *ltr;
248 const char *tld;
249 char *dot_tld;
250 char *zonestr;
251 struct GNUNET_CRYPTO_PublicKey pkey;
252
253 ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
254 ltr->gns_handle = handle;
255 ltr->name = GNUNET_strdup (name);
256 ltr->type = type;
257 ltr->options = options;
258 ltr->lookup_proc = proc;
259 ltr->lookup_proc_cls = proc_cls;
260 /* start with trivial case: TLD is zkey */
261 tld = get_tld (ltr->name);
262 if (GNUNET_OK ==
263 GNUNET_CRYPTO_public_key_from_string (tld, &pkey))
264 {
265 LOG (GNUNET_ERROR_TYPE_DEBUG,
266 "`%s' seems to be a valid zone key\n", tld);
267 eat_tld (ltr->name, tld);
268 lookup_with_public_key (ltr, &pkey);
269 return ltr;
270 }
271
272 /* second case: domain is mapped in our configuration file */
273 for (const char *domain = name; NULL != domain;
274 domain = strchr (domain, (unsigned char) '.'))
275 {
276 if ('.' == domain[0])
277 domain++;
278 GNUNET_asprintf (&dot_tld, ".%s", domain);
279 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (handle->cfg,
280 "gns",
281 dot_tld,
282 &zonestr))
283 {
284 if (GNUNET_OK !=
285 GNUNET_CRYPTO_public_key_from_string (zonestr,
286 &pkey))
287 {
288 GNUNET_log_config_invalid (
289 GNUNET_ERROR_TYPE_ERROR,
290 "gns",
291 dot_tld,
292 _ ("Expected a base32-encoded public zone key\n"));
293 GNUNET_free (zonestr);
294 GNUNET_free (dot_tld);
295 GNUNET_free (ltr->name);
296 GNUNET_free (ltr);
297 return NULL;
298 }
299 eat_tld (ltr->name, &dot_tld[1]);
300 GNUNET_free (zonestr);
301 GNUNET_free (dot_tld);
302 lookup_with_public_key (ltr, &pkey);
303 return ltr;
304 }
305 GNUNET_free (dot_tld);
306 }
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "`%s' should be a valid ego\n", ltr->name);
309 ltr->id_co =
310 GNUNET_IDENTITY_ego_lookup_by_suffix (ltr->gns_handle->cfg,
311 ltr->name,
312 &identity_zone_cb,
313 ltr);
314 if (NULL == ltr->id_co)
315 {
316 GNUNET_free (ltr->name);
317 GNUNET_free (ltr);
318 return NULL;
319 }
320 return ltr;
321}
322
323
324/**
325 * Cancel pending lookup request
326 *
327 * @param ltr the lookup request to cancel
328 * @return closure from the lookup result processor
329 */
330void *
331GNUNET_GNS_lookup_with_tld_cancel (struct GNUNET_GNS_LookupWithTldRequest *ltr)
332{
333 void *ret = ltr->lookup_proc_cls;
334
335 if (NULL != ltr->id_co)
336 {
337 GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (ltr->id_co);
338 ltr->id_co = NULL;
339 }
340 if (NULL != ltr->lr)
341 {
342 GNUNET_GNS_lookup_cancel (ltr->lr);
343 ltr->lr = NULL;
344 }
345 GNUNET_free (ltr->longest_match);
346 GNUNET_free (ltr->name);
347 GNUNET_free (ltr);
348 return ret;
349}
350
351
352/* end of gns_tld_api.c */