X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgns%2Fgnunet-service-gns.c;h=65c232f9374213d2ba73553d7461a140f78c3496;hb=c29a8124f885f28f287e91ce7a0dabcdd6b17d50;hp=cec31ff480fbd0bf0f267769ce04060f15879e26;hpb=3cb90c74c5f591fd2541d154a8e7b05a1c2f4539;p=oweals%2Fgnunet.git diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c index cec31ff48..65c232f93 100644 --- a/src/gns/gnunet-service-gns.c +++ b/src/gns/gnunet-service-gns.c @@ -1,21 +1,21 @@ /* This file is part of GNUnet. - Copyright (C) 2011-2013 GNUnet e.V. + Copyright (C) 2011-2018 GNUnet e.V. - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Affero General Public License for more details. - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file gns/gnunet-service-gns.c @@ -29,14 +29,11 @@ #include "gnunet_dnsparser_lib.h" #include "gnunet_dht_service.h" #include "gnunet_namecache_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_identity_service.h" +#include "gnunet_gnsrecord_lib.h" #include "gnunet_gns_service.h" #include "gnunet_statistics_service.h" #include "gns.h" #include "gnunet-service-gns_resolver.h" -#include "gnunet-service-gns_reverser.h" -#include "gnunet-service-gns_shorten.h" #include "gnunet-service-gns_interceptor.h" #include "gnunet_protocols.h" @@ -47,7 +44,7 @@ struct GnsClient; /** - * Handle to a lookup operation from api + * Handle to a lookup operation from client via API. */ struct ClientLookupHandle { @@ -61,7 +58,7 @@ struct ClientLookupHandle * We keep these in a DLL. */ struct ClientLookupHandle *prev; - + /** * Client handle */ @@ -72,11 +69,6 @@ struct ClientLookupHandle */ struct GNS_ResolverHandle *lookup; - /** - * Active handle for a reverse lookup - */ - struct GNS_ReverserHandle *rev_lookup; - /** * request id */ @@ -84,6 +76,10 @@ struct ClientLookupHandle }; + +/** + * Information we track per connected client. + */ struct GnsClient { /** @@ -108,6 +104,38 @@ struct GnsClient }; +/** + * Representation of a TLD, mapping the respective TLD string + * (i.e. ".gnu") to the respective public key of the zone. + */ +struct GNS_TopLevelDomain +{ + + /** + * Kept in a DLL, as there are unlikely enough of these to + * warrant a hash map. + */ + struct GNS_TopLevelDomain *next; + + /** + * Kept in a DLL, as there are unlikely enough of these to + * warrant a hash map. + */ + struct GNS_TopLevelDomain *prev; + + /** + * Public key associated with the @a tld. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey pkey; + + /** + * Top-level domain as a string, including leading ".". + */ + char *tld; + +}; + + /** * Our handle to the DHT */ @@ -119,73 +147,106 @@ static struct GNUNET_DHT_Handle *dht_handle; static struct GNUNET_NAMECACHE_Handle *namecache_handle; /** - * Our handle to the namestore service + * #GNUNET_YES if ipv6 is supported */ -static struct GNUNET_NAMESTORE_Handle *namestore_handle; +static int v6_enabled; /** - * Our handle to the identity service + * #GNUNET_YES if ipv4 is supported */ -static struct GNUNET_IDENTITY_Handle *identity_handle; +static int v4_enabled; /** - * Our handle to the identity operation to find the master zone - * for intercepted queries. + * Handle to the statistics service */ -static struct GNUNET_IDENTITY_Operation *identity_op; +static struct GNUNET_STATISTICS_Handle *statistics; /** - * #GNUNET_YES if ipv6 is supported + * Head of DLL of TLDs we map to GNS zones. */ -static int v6_enabled; +static struct GNS_TopLevelDomain *tld_head; /** - * #GNUNET_YES if ipv4 is supported + * Tail of DLL of TLDs we map to GNS zones. */ -static int v4_enabled; +static struct GNS_TopLevelDomain *tld_tail; + /** - * Handle to the statistics service + * Find GNS zone belonging to TLD @a tld. + * + * @param tld_str top-level domain to look up + * @param[out] pkey public key to set + * @return #GNUNET_YES if @a tld was found #GNUNET_NO if not */ -static struct GNUNET_STATISTICS_Handle *statistics; +int +GNS_find_tld (const char *tld_str, + struct GNUNET_CRYPTO_EcdsaPublicKey *pkey) +{ + if ('\0' == *tld_str) + return GNUNET_NO; + for (struct GNS_TopLevelDomain *tld = tld_head; + NULL != tld; + tld = tld->next) + { + if (0 == strcasecmp (tld_str, + tld->tld)) + { + *pkey = tld->pkey; + return GNUNET_YES; + } + } + if (GNUNET_OK == + GNUNET_GNSRECORD_zkey_to_pkey (tld_str + 1, + pkey)) + return GNUNET_YES; /* TLD string *was* the public key */ + return GNUNET_NO; +} + + +/** + * Obtain the TLD of the given @a name. + * + * @param name a name + * @return the part of @a name after the last ".", + * or @a name if @a name does not contain a "." + */ +const char * +GNS_get_tld (const char *name) +{ + const char *tld; + + tld = strrchr (name, + (unsigned char) '.'); + if (NULL == tld) + tld = name; + else + tld++; /* skip the '.' */ + return tld; +} /** * Task run during shutdown. * - * @param cls unused - * @param tc unused + * @param cls unused, NULL */ static void shutdown_task (void *cls) { + struct GNS_TopLevelDomain *tld; + + (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down!\n"); GNS_interceptor_done (); - if (NULL != identity_op) - { - GNUNET_IDENTITY_cancel (identity_op); - identity_op = NULL; - } - if (NULL != identity_handle) - { - GNUNET_IDENTITY_disconnect (identity_handle); - identity_handle = NULL; - } GNS_resolver_done (); - GNS_reverse_done (); - GNS_shorten_done (); if (NULL != statistics) { GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); statistics = NULL; } - if (NULL != namestore_handle) - { - GNUNET_NAMESTORE_disconnect (namestore_handle); - namestore_handle = NULL; - } if (NULL != namecache_handle) { GNUNET_NAMECACHE_disconnect (namecache_handle); @@ -196,6 +257,14 @@ shutdown_task (void *cls) GNUNET_DHT_disconnect (dht_handle); dht_handle = NULL; } + while (NULL != (tld = tld_head)) + { + GNUNET_CONTAINER_DLL_remove (tld_head, + tld_tail, + tld); + GNUNET_free (tld->tld); + GNUNET_free (tld); + } } @@ -214,6 +283,7 @@ client_disconnect_cb (void *cls, struct ClientLookupHandle *clh; struct GnsClient *gc = app_ctx; + (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); @@ -221,15 +291,12 @@ client_disconnect_cb (void *cls, { if (NULL != clh->lookup) GNS_resolver_lookup_cancel (clh->lookup); - if (NULL != clh->rev_lookup) - GNS_reverse_lookup_cancel (clh->rev_lookup); GNUNET_CONTAINER_DLL_remove (gc->clh_head, gc->clh_tail, clh); GNUNET_free (clh); } - - GNUNET_free (gc); + GNUNET_free (gc); } @@ -247,6 +314,8 @@ client_connect_cb (void *cls, struct GNUNET_MQ_Handle *mq) { struct GnsClient *gc; + + (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); @@ -265,30 +334,48 @@ client_connect_cb (void *cls, * @param rd the record data */ static void -send_lookup_response (void* cls, +send_lookup_response (void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd) { struct ClientLookupHandle *clh = cls; + struct GnsClient *gc = clh->gc; struct GNUNET_MQ_Envelope *env; struct LookupResultMessage *rmsg; - size_t len; + ssize_t len; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending LOOKUP_RESULT message with %u results\n", (unsigned int) rd_count); - - len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); + len = GNUNET_GNSRECORD_records_get_size (rd_count, + rd); + if (len < 0) + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (gc->client); + return; + } + if (len > UINT16_MAX - sizeof (*rmsg)) + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (gc->client); + return; + } env = GNUNET_MQ_msg_extra (rmsg, len, GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT); rmsg->id = clh->request_id; rmsg->rd_count = htonl (rd_count); - GNUNET_GNSRECORD_records_serialize (rd_count, rd, len, - (char*) &rmsg[1]); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->gc->client), + GNUNET_assert (len == + GNUNET_GNSRECORD_records_serialize (rd_count, + rd, + len, + (char*) &rmsg[1])); + GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (gc->client), env); - GNUNET_CONTAINER_DLL_remove (clh->gc->clh_head, clh->gc->clh_tail, clh); + GNUNET_CONTAINER_DLL_remove (gc->clh_head, + gc->clh_tail, + clh); GNUNET_free (clh); GNUNET_STATISTICS_update (statistics, "Completed lookups", 1, @@ -299,47 +386,6 @@ send_lookup_response (void* cls, GNUNET_NO); } -/** - * Reply to client with the result from our reverse lookup. - * - * @param cls the closure (our client lookup handle) - * @param rd_count the number of records in @a rd - * @param rd the record data - */ -static void -send_reverse_lookup_response (void* cls, - const char *name) -{ - struct ClientLookupHandle *clh = cls; - struct GNUNET_MQ_Envelope *env; - struct ReverseLookupResultMessage *rmsg; - size_t len; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending LOOKUP_RESULT message with %s\n", - name); - - if (NULL == name) - len = 1; - else - len = strlen (name) + 1; - env = GNUNET_MQ_msg_extra (rmsg, - len, - GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP_RESULT); - rmsg->id = clh->request_id; - if (1 < len) - GNUNET_memcpy ((char*) &rmsg[1], - name, - strlen (name)); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->gc->client), - env); - GNUNET_CONTAINER_DLL_remove (clh->gc->clh_head, clh->gc->clh_tail, clh); - GNUNET_free (clh); - GNUNET_STATISTICS_update (statistics, - "Completed reverse lookups", 1, - GNUNET_NO); -} - /** * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message @@ -352,18 +398,12 @@ static int check_lookup (void *cls, const struct LookupMessage *l_msg) { - size_t msg_size; - const char* name; + size_t nlen; - msg_size = ntohs (l_msg->header.size); - if (msg_size < sizeof (struct LookupMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - name = (const char *) &l_msg[1]; - if ( ('\0' != name[msg_size - sizeof (struct LookupMessage) - 1]) || - (strlen (name) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) ) + (void) cls; + GNUNET_MQ_check_zero_termination (l_msg); + nlen = ntohs (l_msg->header.size) - sizeof (struct LookupMessage); + if (nlen > GNUNET_DNSPARSER_MAX_NAME_LENGTH) { GNUNET_break (0); return GNUNET_SYSERR; @@ -371,6 +411,7 @@ check_lookup (void *cls, return GNUNET_OK; } + /** * Handle lookup requests from client * @@ -387,20 +428,18 @@ handle_lookup (void *cls, struct ClientLookupHandle *clh; char *nameptr = name; const char *utf_in; - const struct GNUNET_CRYPTO_EcdsaPrivateKey *key; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received LOOKUP message\n"); GNUNET_SERVICE_client_continue (gc->client); - if (GNUNET_YES == ntohs (sh_msg->have_key)) - key = &sh_msg->shorten_key; - else - key = NULL; utf_in = (const char *) &sh_msg[1]; - GNUNET_STRINGS_utf8_tolower (utf_in, nameptr); - + GNUNET_STRINGS_utf8_tolower (utf_in, + nameptr); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received LOOKUP `%s' message\n", + name); clh = GNUNET_new (struct ClientLookupHandle); - GNUNET_CONTAINER_DLL_insert (gc->clh_head, gc->clh_tail, clh); + GNUNET_CONTAINER_DLL_insert (gc->clh_head, + gc->clh_tail, + clh); clh->gc = gc; clh->request_id = sh_msg->id; if ( (GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) && @@ -408,7 +447,9 @@ handle_lookup (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LOOKUP: Query for A record but AF_INET not supported!"); - send_lookup_response (clh, 0, NULL); + send_lookup_response (clh, + 0, + NULL); return; } if ( (GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) && @@ -416,13 +457,14 @@ handle_lookup (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LOOKUP: Query for AAAA record but AF_INET6 not supported!"); - send_lookup_response (clh, 0, NULL); + send_lookup_response (clh, + 0, + NULL); return; } clh->lookup = GNS_resolver_lookup (&sh_msg->zone, ntohl (sh_msg->type), name, - key, (enum GNUNET_GNS_LocalOptions) ntohs (sh_msg->options), &send_lookup_response, clh); GNUNET_STATISTICS_update (statistics, @@ -430,135 +472,46 @@ handle_lookup (void *cls, 1, GNUNET_NO); } -/** - * Handle reverse lookup requests from client - * - * @param cls the closure - * @param client the client - * @param message the message - */ -static void -handle_rev_lookup (void *cls, - const struct ReverseLookupMessage *sh_msg) -{ - struct GnsClient *gc = cls; - struct ClientLookupHandle *clh; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received REVERSE_LOOKUP message\n"); - GNUNET_SERVICE_client_continue (gc->client); - - clh = GNUNET_new (struct ClientLookupHandle); - GNUNET_CONTAINER_DLL_insert (gc->clh_head, gc->clh_tail, clh); - clh->gc = gc; - clh->request_id = sh_msg->id; - clh->rev_lookup = GNS_reverse_lookup (&sh_msg->zone_pkey, - &sh_msg->root_pkey, - &send_reverse_lookup_response, - clh); - GNUNET_STATISTICS_update (statistics, - "Reverse lookup attempts", - 1, GNUNET_NO); -} - /** - * Method called to inform about the ego to be used for the master zone - * for DNS interceptions. + * Reads the configuration and populates TLDs * - * This function is only called ONCE, and 'NULL' being passed in - * @a ego does indicate that interception is not configured. - * If @a ego is non-NULL, we should start to intercept DNS queries - * and resolve ".gnu" queries using the given ego as the master zone. - * - * @param cls closure, our `const struct GNUNET_CONFIGURATION_Handle *c` - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param name name assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used + * @param cls unused + * @param section name of section in config, always "gns" + * @param option name of the option, TLDs start with "." + * @param value value for the option, public key for TLDs */ static void -identity_reverse_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) +read_service_conf (void *cls, + const char *section, + const char *option, + const char *value) { - identity_op = NULL; - - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("No ego configured for `%s`\n"), - "gns-master"); + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + struct GNS_TopLevelDomain *tld; + (void) cls; + (void) section; + if (option[0] != '.') return; - } - if (GNUNET_SYSERR == - GNS_reverse_init (namestore_handle, - GNUNET_IDENTITY_ego_get_private_key (ego), - name)) + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (value, + strlen (value), + &pk, + sizeof (pk))) { - GNUNET_break (0); - GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); - return; - } -} - - -/** - * Method called to inform about the ego to be used for the master zone - * for DNS interceptions. - * - * This function is only called ONCE, and 'NULL' being passed in - * @a ego does indicate that interception is not configured. - * If @a ego is non-NULL, we should start to intercept DNS queries - * and resolve ".gnu" queries using the given ego as the master zone. - * - * @param cls closure, our `const struct GNUNET_CONFIGURATION_Handle *c` - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param name name assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -identity_intercept_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_CRYPTO_EcdsaPublicKey dns_root; - identity_op = NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Looking for gns-intercept ego\n"); - identity_op = GNUNET_IDENTITY_get (identity_handle, - "gns-reverse", - &identity_reverse_cb, - (void*)cfg); - - - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("No ego configured for `%s`\n"), - "gns-intercept"); - - return; - } - GNUNET_IDENTITY_ego_get_public_key (ego, - &dns_root); - if (GNUNET_SYSERR == - GNS_interceptor_init (&dns_root, cfg)) - { - GNUNET_break (0); - GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + option, + _("Properly base32-encoded public key required")); return; } + tld = GNUNET_new (struct GNS_TopLevelDomain); + tld->tld = GNUNET_strdup (&option[1]); + tld->pkey = pk; + GNUNET_CONTAINER_DLL_insert (tld_head, + tld_tail, + tld); } @@ -576,17 +529,13 @@ run (void *cls, { unsigned long long max_parallel_bg_queries = 16; + GNUNET_CONFIGURATION_iterate_section_values (c, + "gns", + &read_service_conf, + NULL); v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6); - v4_enabled = GNUNET_NETWORK_test_pf (PF_INET); - namestore_handle = GNUNET_NAMESTORE_connect (c); - if (NULL == namestore_handle) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to connect to the namestore!\n")); - GNUNET_SCHEDULER_shutdown (); - return; - } - namecache_handle = GNUNET_NAMECACHE_connect (c); + v4_enabled = GNUNET_NETWORK_test_pf (PF_INET); + namecache_handle = GNUNET_NAMECACHE_connect (c); if (NULL == namecache_handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -610,36 +559,30 @@ run (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not connect to DHT!\n")); - GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + GNUNET_SCHEDULER_add_now (&shutdown_task, + NULL); return; } - - identity_handle = GNUNET_IDENTITY_connect (c, - NULL, - NULL); - if (NULL == identity_handle) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Could not connect to identity service!\n"); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Looking for gns-intercept ego\n"); - identity_op = GNUNET_IDENTITY_get (identity_handle, - "gns-intercept", - &identity_intercept_cb, - (void *) c); - } GNS_resolver_init (namecache_handle, dht_handle, c, max_parallel_bg_queries); - GNS_shorten_init (namestore_handle, - namecache_handle, - dht_handle); - statistics = GNUNET_STATISTICS_create ("gns", c); - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); + if ( (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (c, + "gns", + "INTERCEPT_DNS")) && + (GNUNET_SYSERR == + GNS_interceptor_init (c)) ) + { + GNUNET_break (0); + GNUNET_SCHEDULER_add_now (&shutdown_task, + NULL); + return; + } + statistics = GNUNET_STATISTICS_create ("gns", + c); + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, + NULL); } @@ -657,10 +600,6 @@ GNUNET_SERVICE_MAIN GNUNET_MESSAGE_TYPE_GNS_LOOKUP, struct LookupMessage, NULL), - GNUNET_MQ_hd_fixed_size (rev_lookup, - GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP, - struct ReverseLookupMessage, - NULL), GNUNET_MQ_handler_end());