2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file gns/gnunet-service-gns.c
22 * @brief GNU Name System (main service)
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_dns_service.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_dht_service.h"
31 #include "gnunet_namecache_service.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_identity_service.h"
34 #include "gnunet_gns_service.h"
35 #include "gnunet_statistics_service.h"
37 #include "gnunet-service-gns_resolver.h"
38 #include "gnunet-service-gns_reverser.h"
39 #include "gnunet-service-gns_shorten.h"
40 #include "gnunet-service-gns_interceptor.h"
41 #include "gnunet_protocols.h"
50 * Handle to a lookup operation from api
52 struct ClientLookupHandle
56 * We keep these in a DLL.
58 struct ClientLookupHandle *next;
61 * We keep these in a DLL.
63 struct ClientLookupHandle *prev;
71 * Active handle for the lookup.
73 struct GNS_ResolverHandle *lookup;
87 struct GNUNET_SERVICE_Client *client;
92 struct GNUNET_MQ_Handle *mq;
97 struct ClientLookupHandle *clh_head;
102 struct ClientLookupHandle *clh_tail;
107 * Our handle to the DHT
109 static struct GNUNET_DHT_Handle *dht_handle;
112 * Our handle to the namecache service
114 static struct GNUNET_NAMECACHE_Handle *namecache_handle;
117 * Our handle to the namestore service
119 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
122 * Our handle to the identity service
124 static struct GNUNET_IDENTITY_Handle *identity_handle;
127 * Our handle to the identity operation to find the master zone
128 * for intercepted queries.
130 static struct GNUNET_IDENTITY_Operation *identity_op;
133 * #GNUNET_YES if ipv6 is supported
135 static int v6_enabled;
138 * #GNUNET_YES if ipv4 is supported
140 static int v4_enabled;
143 * Handle to the statistics service
145 static struct GNUNET_STATISTICS_Handle *statistics;
149 * Task run during shutdown.
155 shutdown_task (void *cls)
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159 GNS_interceptor_done ();
160 if (NULL != identity_op)
162 GNUNET_IDENTITY_cancel (identity_op);
165 if (NULL != identity_handle)
167 GNUNET_IDENTITY_disconnect (identity_handle);
168 identity_handle = NULL;
170 GNS_resolver_done ();
171 if (NULL != statistics)
173 GNUNET_STATISTICS_destroy (statistics,
177 if (NULL != namestore_handle)
179 GNUNET_NAMESTORE_disconnect (namestore_handle);
180 namestore_handle = NULL;
182 if (NULL != namecache_handle)
184 GNUNET_NAMECACHE_disconnect (namecache_handle);
185 namecache_handle = NULL;
187 if (NULL != dht_handle)
189 GNUNET_DHT_disconnect (dht_handle);
196 * Called whenever a client is disconnected.
199 * @param client identification of the client
200 * @param app_ctx @a client
203 client_disconnect_cb (void *cls,
204 struct GNUNET_SERVICE_Client *client,
207 struct ClientLookupHandle *clh;
208 struct GnsClient *gc = app_ctx;
210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
211 "Client %p disconnected\n",
213 while (NULL != (clh = gc->clh_head))
215 if (NULL != clh->lookup)
216 GNS_resolver_lookup_cancel (clh->lookup);
217 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
228 * Add a client to our list of active clients.
231 * @param client client to add
232 * @param mq message queue for @a client
233 * @return internal namestore client structure for this client
236 client_connect_cb (void *cls,
237 struct GNUNET_SERVICE_Client *client,
238 struct GNUNET_MQ_Handle *mq)
240 struct GnsClient *gc;
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242 "Client %p connected\n",
244 gc = GNUNET_new (struct GnsClient);
252 * Reply to client with the result from our lookup.
254 * @param cls the closure (our client lookup handle)
255 * @param rd_count the number of records in @a rd
256 * @param rd the record data
259 send_lookup_response (void* cls,
261 const struct GNUNET_GNSRECORD_Data *rd)
263 struct ClientLookupHandle *clh = cls;
264 struct GNUNET_MQ_Envelope *env;
265 struct LookupResultMessage *rmsg;
268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
269 "Sending LOOKUP_RESULT message with %u results\n",
270 (unsigned int) rd_count);
272 len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
273 env = GNUNET_MQ_msg_extra (rmsg,
275 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
276 rmsg->id = clh->request_id;
277 rmsg->rd_count = htonl (rd_count);
278 GNUNET_GNSRECORD_records_serialize (rd_count, rd, len,
280 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->gc->client),
282 GNUNET_CONTAINER_DLL_remove (clh->gc->clh_head,
286 GNUNET_STATISTICS_update (statistics,
287 "Completed lookups", 1,
289 GNUNET_STATISTICS_update (statistics,
297 * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message
299 * @param cls client sending the message
300 * @param l_msg message of type `struct LookupMessage`
301 * @return #GNUNET_OK if @a l_msg is well-formed
304 check_lookup (void *cls,
305 const struct LookupMessage *l_msg)
310 msg_size = ntohs (l_msg->header.size);
311 if (msg_size < sizeof (struct LookupMessage))
314 return GNUNET_SYSERR;
316 name = (const char *) &l_msg[1];
317 if ( ('\0' != name[msg_size - sizeof (struct LookupMessage) - 1]) ||
318 (strlen (name) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) )
321 return GNUNET_SYSERR;
328 * Handle lookup requests from client
330 * @param cls the closure
331 * @param client the client
332 * @param message the message
335 handle_lookup (void *cls,
336 const struct LookupMessage *sh_msg)
338 struct GnsClient *gc = cls;
339 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
340 struct ClientLookupHandle *clh;
341 char *nameptr = name;
344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
345 "Received LOOKUP message\n");
346 GNUNET_SERVICE_client_continue (gc->client);
347 utf_in = (const char *) &sh_msg[1];
348 GNUNET_STRINGS_utf8_tolower (utf_in, nameptr);
350 clh = GNUNET_new (struct ClientLookupHandle);
351 GNUNET_CONTAINER_DLL_insert (gc->clh_head,
355 clh->request_id = sh_msg->id;
356 if ( (GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
357 (GNUNET_OK != v4_enabled) )
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "LOOKUP: Query for A record but AF_INET not supported!");
361 send_lookup_response (clh, 0, NULL);
364 if ( (GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) &&
365 (GNUNET_OK != v6_enabled) )
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368 "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
369 send_lookup_response (clh, 0, NULL);
372 clh->lookup = GNS_resolver_lookup (&sh_msg->zone,
373 ntohl (sh_msg->type),
375 (enum GNUNET_GNS_LocalOptions) ntohs (sh_msg->options),
376 &send_lookup_response, clh);
377 GNUNET_STATISTICS_update (statistics,
384 * Method called to inform about the ego to be used for the master zone
385 * for DNS interceptions.
387 * This function is only called ONCE, and 'NULL' being passed in
388 * @a ego does indicate that interception is not configured.
389 * If @a ego is non-NULL, we should start to intercept DNS queries
390 * and resolve ".gnu" queries using the given ego as the master zone.
392 * @param cls closure, our `const struct GNUNET_CONFIGURATION_Handle *c`
393 * @param ego ego handle
394 * @param ctx context for application to store data for this ego
395 * (during the lifetime of this process, initially NULL)
396 * @param name name assigned by the user for this ego,
397 * NULL if the user just deleted the ego and it
398 * must thus no longer be used
401 identity_intercept_cb (void *cls,
402 struct GNUNET_IDENTITY_Ego *ego,
406 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
407 struct GNUNET_CRYPTO_EcdsaPublicKey dns_root;
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411 "Looking for gns-intercept ego\n");
414 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
415 _("No ego configured for `%s`\n"),
420 GNUNET_IDENTITY_ego_get_public_key (ego,
423 GNS_interceptor_init (&dns_root,
427 GNUNET_SCHEDULER_add_now (&shutdown_task,
435 * Process GNS requests.
438 * @param server the initialized server
439 * @param c configuration to use
443 const struct GNUNET_CONFIGURATION_Handle *c,
444 struct GNUNET_SERVICE_Handle *service)
446 unsigned long long max_parallel_bg_queries = 16;
448 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
449 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
450 namestore_handle = GNUNET_NAMESTORE_connect (c);
451 if (NULL == namestore_handle)
453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
454 _("Failed to connect to the namestore!\n"));
455 GNUNET_SCHEDULER_shutdown ();
458 namecache_handle = GNUNET_NAMECACHE_connect (c);
459 if (NULL == namecache_handle)
461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
462 _("Failed to connect to the namecache!\n"));
463 GNUNET_SCHEDULER_shutdown ();
467 GNUNET_CONFIGURATION_get_value_number (c,
469 "MAX_PARALLEL_BACKGROUND_QUERIES",
470 &max_parallel_bg_queries))
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473 "Number of allowed parallel background queries: %llu\n",
474 max_parallel_bg_queries);
476 dht_handle = GNUNET_DHT_connect (c,
477 (unsigned int) max_parallel_bg_queries);
478 if (NULL == dht_handle)
480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
481 _("Could not connect to DHT!\n"));
482 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
486 identity_handle = GNUNET_IDENTITY_connect (c,
489 if (NULL == identity_handle)
491 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
492 "Could not connect to identity service!\n");
496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497 "Looking for gns-intercept ego\n");
498 identity_op = GNUNET_IDENTITY_get (identity_handle,
500 &identity_intercept_cb,
503 GNS_resolver_init (namecache_handle,
506 max_parallel_bg_queries);
507 statistics = GNUNET_STATISTICS_create ("gns", c);
508 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
514 * Define "main" method using service macro.
518 GNUNET_SERVICE_OPTION_NONE,
521 &client_disconnect_cb,
523 GNUNET_MQ_hd_var_size (lookup,
524 GNUNET_MESSAGE_TYPE_GNS_LOOKUP,
525 struct LookupMessage,
527 GNUNET_MQ_handler_end());
530 /* end of gnunet-service-gns.c */