aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gnunet-service-gns.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2023-10-19 11:33:18 +0200
committerMartin Schanzenbach <schanzen@gnunet.org>2023-10-19 11:33:18 +0200
commit7c7d819e8e03dadb91935d5ae91aa921cc7b86c7 (patch)
tree9327ae110e5e64c99901cd853d3d36e23f39aaee /src/gns/gnunet-service-gns.c
parentdf59c19d712a4339f7c75c76942c1a4f86bf2e5b (diff)
downloadgnunet-7c7d819e8e03dadb91935d5ae91aa921cc7b86c7.tar.gz
gnunet-7c7d819e8e03dadb91935d5ae91aa921cc7b86c7.zip
BUILD: Move gns/zonemaster to service
Diffstat (limited to 'src/gns/gnunet-service-gns.c')
-rw-r--r--src/gns/gnunet-service-gns.c618
1 files changed, 0 insertions, 618 deletions
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
deleted file mode 100644
index aaf82a557..000000000
--- a/src/gns/gnunet-service-gns.c
+++ /dev/null
@@ -1,618 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-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/gnunet-service-gns.c
22 * @brief GNU Name System (main service)
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_dns_service.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_namecache_service.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_gns_service.h"
33#include "gnunet_statistics_service.h"
34#include "gns.h"
35#include "gnunet-service-gns_resolver.h"
36#include "gnunet-service-gns_interceptor.h"
37#include "gnunet_protocols.h"
38
39
40/**
41 * GnsClient prototype
42 */
43struct GnsClient;
44
45/**
46 * Handle to a lookup operation from client via API.
47 */
48struct ClientLookupHandle
49{
50 /**
51 * We keep these in a DLL.
52 */
53 struct ClientLookupHandle *next;
54
55 /**
56 * We keep these in a DLL.
57 */
58 struct ClientLookupHandle *prev;
59
60 /**
61 * Client handle
62 */
63 struct GnsClient *gc;
64
65 /**
66 * Active handle for the lookup.
67 */
68 struct GNS_ResolverHandle *lookup;
69
70 /**
71 * request id
72 */
73 uint32_t request_id;
74};
75
76
77/**
78 * Information we track per connected client.
79 */
80struct GnsClient
81{
82 /**
83 * The client
84 */
85 struct GNUNET_SERVICE_Client *client;
86
87 /**
88 * The MQ
89 */
90 struct GNUNET_MQ_Handle *mq;
91
92 /**
93 * Head of the DLL.
94 */
95 struct ClientLookupHandle *clh_head;
96
97 /**
98 * Tail of the DLL.
99 */
100 struct ClientLookupHandle *clh_tail;
101};
102
103
104/**
105 * Representation of a TLD, mapping the respective TLD string
106 * (e.g. ".gnu") to the respective public key of the zone.
107 */
108struct GNS_TopLevelDomain
109{
110 /**
111 * Kept in a DLL, as there are unlikely enough of these to
112 * warrant a hash map.
113 */
114 struct GNS_TopLevelDomain *next;
115
116 /**
117 * Kept in a DLL, as there are unlikely enough of these to
118 * warrant a hash map.
119 */
120 struct GNS_TopLevelDomain *prev;
121
122 /**
123 * Public key associated with the @a tld.
124 */
125 struct GNUNET_CRYPTO_PublicKey pkey;
126
127 /**
128 * Top-level domain as a string, including leading ".".
129 */
130 char *tld;
131};
132
133
134/**
135 * Our handle to the DHT
136 */
137static struct GNUNET_DHT_Handle *dht_handle;
138
139/**
140 * Our handle to the namecache service
141 */
142static struct GNUNET_NAMECACHE_Handle *namecache_handle;
143
144/**
145 * #GNUNET_YES if ipv6 is supported
146 */
147static int v6_enabled;
148
149/**
150 * #GNUNET_YES if ipv4 is supported
151 */
152static int v4_enabled;
153
154/**
155 * Handle to the statistics service
156 */
157static struct GNUNET_STATISTICS_Handle *statistics;
158
159/**
160 * Head of DLL of TLDs we map to GNS zones.
161 */
162static struct GNS_TopLevelDomain *tld_head;
163
164/**
165 * Tail of DLL of TLDs we map to GNS zones.
166 */
167static struct GNS_TopLevelDomain *tld_tail;
168
169
170/**
171 * Find GNS zone belonging to TLD @a tld.
172 *
173 * @param tld_str top-level domain to look up
174 * @param[out] pkey public key to set
175 * @return #GNUNET_YES if @a tld was found #GNUNET_NO if not
176 */
177int
178GNS_find_tld (const char *tld_str,
179 struct GNUNET_CRYPTO_PublicKey *pkey)
180{
181 if ('\0' == *tld_str)
182 return GNUNET_NO;
183 for (struct GNS_TopLevelDomain *tld = tld_head;
184 NULL != tld;
185 tld = tld->next)
186 {
187 if (0 == strcasecmp (tld_str,
188 tld->tld))
189 {
190 *pkey = tld->pkey;
191 return GNUNET_YES;
192 }
193 }
194 if (GNUNET_OK ==
195 GNUNET_GNSRECORD_zkey_to_pkey (tld_str + 1,
196 pkey))
197 return GNUNET_YES; /* TLD string *was* the public key */
198 return GNUNET_NO;
199}
200
201
202/**
203 * Obtain the TLD of the given @a name.
204 *
205 * @param name a name
206 * @return the part of @a name after the last ".",
207 * or @a name if @a name does not contain a "."
208 */
209const char *
210GNS_get_tld (const char *name)
211{
212 const char *tld;
213
214 tld = strrchr (name,
215 (unsigned char) '.');
216 if (NULL == tld)
217 tld = name;
218 else
219 tld++; /* skip the '.' */
220 return tld;
221}
222
223
224/**
225 * Task run during shutdown.
226 *
227 * @param cls unused, NULL
228 */
229static void
230shutdown_task (void *cls)
231{
232 struct GNS_TopLevelDomain *tld;
233
234 (void) cls;
235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236 "Shutting down!\n");
237 GNS_interceptor_done ();
238 GNS_resolver_done ();
239 if (NULL != statistics)
240 {
241 GNUNET_STATISTICS_destroy (statistics,
242 GNUNET_NO);
243 statistics = NULL;
244 }
245 if (NULL != namecache_handle)
246 {
247 GNUNET_NAMECACHE_disconnect (namecache_handle);
248 namecache_handle = NULL;
249 }
250 if (NULL != dht_handle)
251 {
252 GNUNET_DHT_disconnect (dht_handle);
253 dht_handle = NULL;
254 }
255 while (NULL != (tld = tld_head))
256 {
257 GNUNET_CONTAINER_DLL_remove (tld_head,
258 tld_tail,
259 tld);
260 GNUNET_free (tld->tld);
261 GNUNET_free (tld);
262 }
263}
264
265
266/**
267 * Called whenever a client is disconnected.
268 *
269 * @param cls closure
270 * @param client identification of the client
271 * @param app_ctx @a client
272 */
273static void
274client_disconnect_cb (void *cls,
275 struct GNUNET_SERVICE_Client *client,
276 void *app_ctx)
277{
278 struct ClientLookupHandle *clh;
279 struct GnsClient *gc = app_ctx;
280
281 (void) cls;
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Client %p disconnected\n",
284 client);
285 while (NULL != (clh = gc->clh_head))
286 {
287 if (NULL != clh->lookup)
288 GNS_resolver_lookup_cancel (clh->lookup);
289 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
290 gc->clh_tail,
291 clh);
292 GNUNET_free (clh);
293 }
294 GNUNET_free (gc);
295}
296
297
298/**
299 * Add a client to our list of active clients.
300 *
301 * @param cls NULL
302 * @param client client to add
303 * @param mq message queue for @a client
304 * @return internal namestore client structure for this client
305 */
306static void *
307client_connect_cb (void *cls,
308 struct GNUNET_SERVICE_Client *client,
309 struct GNUNET_MQ_Handle *mq)
310{
311 struct GnsClient *gc;
312
313 (void) cls;
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Client %p connected\n",
316 client);
317 gc = GNUNET_new (struct GnsClient);
318 gc->client = client;
319 gc->mq = mq;
320 return gc;
321}
322
323
324/**
325 * Reply to client with the result from our lookup.
326 *
327 * @param cls the closure (our client lookup handle)
328 * @param rd_count the number of records in @a rd
329 * @param rd the record data
330 */
331static void
332send_lookup_response (void *cls,
333 uint32_t rd_count,
334 const struct GNUNET_GNSRECORD_Data *rd)
335{
336 struct ClientLookupHandle *clh = cls;
337 struct GnsClient *gc = clh->gc;
338 struct GNUNET_MQ_Envelope *env;
339 struct LookupResultMessage *rmsg;
340 ssize_t len;
341
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Sending LOOKUP_RESULT message with %u results\n",
344 (unsigned int) rd_count);
345 len = GNUNET_GNSRECORD_records_get_size (rd_count,
346 rd);
347 if (len < 0)
348 {
349 GNUNET_break (0);
350 GNUNET_SERVICE_client_drop (gc->client);
351 return;
352 }
353 if (len > UINT16_MAX - sizeof(*rmsg))
354 {
355 GNUNET_break (0);
356 GNUNET_SERVICE_client_drop (gc->client);
357 return;
358 }
359 env = GNUNET_MQ_msg_extra (rmsg,
360 len,
361 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
362 rmsg->id = clh->request_id;
363 rmsg->rd_count = htonl (rd_count);
364 GNUNET_assert (len ==
365 GNUNET_GNSRECORD_records_serialize (rd_count,
366 rd,
367 len,
368 (char *) &rmsg[1]));
369 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (gc->client),
370 env);
371 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
372 gc->clh_tail,
373 clh);
374 GNUNET_free (clh);
375 GNUNET_STATISTICS_update (statistics,
376 "Completed lookups", 1,
377 GNUNET_NO);
378 GNUNET_STATISTICS_update (statistics,
379 "Records resolved",
380 rd_count,
381 GNUNET_NO);
382}
383
384
385/**
386 * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message
387 *
388 * @param cls client sending the message
389 * @param l_msg message of type `struct LookupMessage`
390 * @return #GNUNET_OK if @a l_msg is well-formed
391 */
392static int
393check_lookup (void *cls,
394 const struct LookupMessage *l_msg)
395{
396 size_t nlen;
397 size_t klen;
398
399 (void) cls;
400 klen = ntohl (l_msg->key_len);
401 nlen = ntohs (l_msg->header.size) - sizeof(struct LookupMessage) - klen;
402 if (nlen > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
403 {
404 GNUNET_break (0);
405 return GNUNET_SYSERR;
406 }
407 return GNUNET_OK;
408}
409
410
411/**
412 * Handle lookup requests from client
413 *
414 * @param cls the closure
415 * @param sh_msg the message
416 */
417static void
418handle_lookup (void *cls,
419 const struct LookupMessage *sh_msg)
420{
421 struct GnsClient *gc = cls;
422 struct ClientLookupHandle *clh;
423 struct GNUNET_CRYPTO_PublicKey zone;
424 const char *name;
425 size_t key_len;
426 size_t read;
427
428 GNUNET_SERVICE_client_continue (gc->client);
429 key_len = ntohl (sh_msg->key_len);
430 clh = GNUNET_new (struct ClientLookupHandle);
431 GNUNET_CONTAINER_DLL_insert (gc->clh_head,
432 gc->clh_tail,
433 clh);
434 clh->gc = gc;
435 clh->request_id = sh_msg->id;
436 if ((GNUNET_SYSERR ==
437 GNUNET_CRYPTO_read_public_key_from_buffer (&sh_msg[1],
438 key_len,
439 &zone,
440 &read)) ||
441 (read != key_len))
442 {
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "LOOKUP: Failed to read zone key!");
445 send_lookup_response (clh,
446 0,
447 NULL);
448 return;
449 }
450 name = (const char *) &sh_msg[1] + key_len;
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 "Received LOOKUP `%s' message\n",
453 name);
454 if ((GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
455 (GNUNET_OK != v4_enabled))
456 {
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "LOOKUP: Query for A record but AF_INET not supported!");
459 send_lookup_response (clh,
460 0,
461 NULL);
462 return;
463 }
464 if ((GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) &&
465 (GNUNET_OK != v6_enabled))
466 {
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468 "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
469 send_lookup_response (clh,
470 0,
471 NULL);
472 return;
473 }
474 clh->lookup = GNS_resolver_lookup (&zone,
475 ntohl (sh_msg->type),
476 name,
477 (enum GNUNET_GNS_LocalOptions) ntohs (
478 sh_msg->options),
479 ntohs (sh_msg->recursion_depth_limit),
480 &send_lookup_response, clh);
481 GNUNET_STATISTICS_update (statistics,
482 "Lookup attempts",
483 1, GNUNET_NO);
484}
485
486
487/**
488 * Reads the configuration and populates TLDs
489 *
490 * @param cls unused
491 * @param section name of section in config, always "gns"
492 * @param option name of the option, TLDs start with "."
493 * @param value value for the option, public key for TLDs
494 */
495static void
496read_service_conf (void *cls,
497 const char *section,
498 const char *option,
499 const char *value)
500{
501 struct GNUNET_CRYPTO_PublicKey pk;
502 struct GNS_TopLevelDomain *tld;
503
504 (void) cls;
505 (void) section;
506 if (option[0] != '.')
507 return;
508 if (GNUNET_OK !=
509 GNUNET_STRINGS_string_to_data (value,
510 strlen (value),
511 &pk,
512 sizeof(pk)))
513 {
514 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
515 section,
516 option,
517 _ (
518 "Properly base32-encoded public key required"));
519 return;
520 }
521 tld = GNUNET_new (struct GNS_TopLevelDomain);
522 tld->tld = GNUNET_strdup (&option[1]);
523 tld->pkey = pk;
524 GNUNET_CONTAINER_DLL_insert (tld_head,
525 tld_tail,
526 tld);
527}
528
529
530/**
531 * Process GNS requests.
532 *
533 * @param cls closure
534 * @param server the initialized server
535 * @param c configuration to use
536 */
537static void
538run (void *cls,
539 const struct GNUNET_CONFIGURATION_Handle *c,
540 struct GNUNET_SERVICE_Handle *service)
541{
542 unsigned long long max_parallel_bg_queries = 16;
543
544 GNUNET_CONFIGURATION_iterate_section_values (c,
545 "gns",
546 &read_service_conf,
547 NULL);
548 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
549 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
550 namecache_handle = GNUNET_NAMECACHE_connect (c);
551 if (NULL == namecache_handle)
552 {
553 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
554 _ ("Failed to connect to the namecache!\n"));
555 GNUNET_SCHEDULER_shutdown ();
556 return;
557 }
558 if (GNUNET_OK ==
559 GNUNET_CONFIGURATION_get_value_number (c,
560 "gns",
561 "MAX_PARALLEL_BACKGROUND_QUERIES",
562 &max_parallel_bg_queries))
563 {
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 "Number of allowed parallel background queries: %llu\n",
566 max_parallel_bg_queries);
567 }
568 dht_handle = GNUNET_DHT_connect (c,
569 (unsigned int) max_parallel_bg_queries);
570 if (NULL == dht_handle)
571 {
572 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573 _ ("Could not connect to DHT!\n"));
574 GNUNET_SCHEDULER_add_now (&shutdown_task,
575 NULL);
576 return;
577 }
578 GNS_resolver_init (namecache_handle,
579 dht_handle,
580 c,
581 max_parallel_bg_queries);
582 if ((GNUNET_YES ==
583 GNUNET_CONFIGURATION_get_value_yesno (c,
584 "gns",
585 "INTERCEPT_DNS")) &&
586 (GNUNET_SYSERR ==
587 GNS_interceptor_init (c)))
588 {
589 GNUNET_break (0);
590 GNUNET_SCHEDULER_add_now (&shutdown_task,
591 NULL);
592 return;
593 }
594 statistics = GNUNET_STATISTICS_create ("gns",
595 c);
596 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
597 NULL);
598}
599
600
601/**
602 * Define "main" method using service macro.
603 */
604GNUNET_SERVICE_MAIN
605 ("gns",
606 GNUNET_SERVICE_OPTION_NONE,
607 &run,
608 &client_connect_cb,
609 &client_disconnect_cb,
610 NULL,
611 GNUNET_MQ_hd_var_size (lookup,
612 GNUNET_MESSAGE_TYPE_GNS_LOOKUP,
613 struct LookupMessage,
614 NULL),
615 GNUNET_MQ_handler_end ());
616
617
618/* end of gnunet-service-gns.c */