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..63b5ac552
--- /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 "gnunet_common.h"
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_constants.h"
30#include "gnunet_arm_service.h"
31#include "gnunet_identity_service.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 * Handle to a lookup request
43 */
44struct GNUNET_GNS_LookupWithTldRequest
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_EgoSuffixLookup *id_co;
75
76 /**
77 * Name of the longest matching ego found so far.
78 * Must be freed on termination.
79 */
80 char *longest_match;
81
82 /**
83 * Ego corresponding to @e longest_match.
84 */
85 struct GNUNET_IDENTITY_Ego *longest_match_ego;
86
87 /**
88 * Desired result record type.
89 */
90 uint32_t type;
91
92 /**
93 * Lookup options.
94 */
95 enum GNUNET_GNS_LocalOptions options;
96};
97
98
99/**
100 * Obtain the TLD of the given @a name.
101 *
102 * @param name a name
103 * @return the part of @a name after the last ".",
104 * or @a name if @a name does not contain a "."
105 */
106static const char *
107get_tld (const char *name)
108{
109 const char *tld;
110
111 tld = strrchr (name, (unsigned char) '.');
112 if (NULL == tld)
113 tld = name;
114 else
115 tld++; /* skip the '.' */
116 return tld;
117}
118
119
120/**
121 * Eat the "TLD" (last bit) of the given @a name.
122 *
123 * @param[in,out] name a name
124 * @param tld what to eat (can be more than just the tld)
125 */
126static void
127eat_tld (char *name, const char *tld)
128{
129 GNUNET_assert (0 < strlen (name));
130 if ((NULL == tld) || (strlen (name) == strlen (tld)))
131 {
132 strcpy (name, GNUNET_GNS_EMPTY_LABEL_AT);
133 }
134 else
135 {
136 GNUNET_assert (strlen (tld) < strlen (name));
137 name[strlen (name) - strlen (tld) - 1] = '\0';
138 }
139}
140
141
142/**
143 * Function called with the result of a GNS lookup.
144 *
145 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
146 * @param rd_count number of records returned
147 * @param rd array of @a rd_count records with the results
148 */
149static void
150process_lookup_result (void *cls,
151 uint32_t rd_count,
152 const struct GNUNET_GNSRECORD_Data *rd)
153{
154 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
155
156 ltr->lr = NULL;
157 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_YES, rd_count, rd);
158 GNUNET_GNS_lookup_with_tld_cancel (ltr);
159}
160
161
162/**
163 * Perform the actual resolution, starting with the zone
164 * identified by the given public key.
165 *
166 * @param pkey public key to use for the zone, can be NULL
167 */
168static void
169lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
170 const struct GNUNET_CRYPTO_PublicKey *pkey)
171{
172 ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
173 ltr->name,
174 pkey,
175 ltr->type,
176 ltr->options,
177 &process_lookup_result,
178 ltr);
179}
180
181
182/**
183 * Method called to with the ego we are to use for the lookup,
184 * when the ego is determined by a name.
185 *
186 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
187 * @param ego ego handle, NULL at the end of the iteration
188 * @param ctx context we could store data to associate with @e ego
189 * @param ego_name name of the ego
190 */
191static void
192identity_zone_cb (void *cls,
193 const struct GNUNET_CRYPTO_PrivateKey *priv,
194 const char *ego_name)
195{
196 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
197 struct GNUNET_CRYPTO_PublicKey pkey;
198
199 ltr->id_co = NULL;
200 if (NULL == priv)
201 {
202 /* no matching ego found */
203 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_NO, 0, NULL);
204 return;
205 }
206 /* Final case: TLD matches one of our egos */
207 if (0 == strcmp (ltr->name, ego_name))
208 {
209 /* name matches ego name perfectly, only "@" remains */
210 strcpy (ltr->name, GNUNET_GNS_EMPTY_LABEL_AT);
211 }
212 else
213 {
214 GNUNET_assert (strlen (ego_name) < strlen (ltr->name));
215 ltr->name[strlen (ltr->name) - strlen (ego_name) - 1] = '\0';
216 }
217 /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
218 if (NULL == strchr (ltr->name, (unsigned char) '.'))
219 ltr->options = GNUNET_GNS_LO_NO_DHT;
220 else
221 ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
222 GNUNET_CRYPTO_key_get_public (priv, &pkey);
223 lookup_with_public_key (ltr, &pkey);
224}
225
226
227enum GNUNET_GenericReturnValue
228GNUNET_GNS_parse_ztld (const char *name,
229 struct GNUNET_CRYPTO_PublicKey *ztld_key)
230{
231 const char *tld;
232
233 /* start with trivial case: TLD is zkey */
234 tld = get_tld (name);
235 return GNUNET_CRYPTO_public_key_from_string (tld, ztld_key);
236}
237
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 if (GNUNET_OK ==
262 GNUNET_GNS_parse_ztld (ltr->name, &pkey))
263 {
264 tld = get_tld (ltr->name);
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 */