From: Christian Grothoff Date: Thu, 18 Oct 2018 12:55:17 +0000 (+0200) Subject: use unique 32-bit IDs for DNS requests to avoid random confusions, handle additional... X-Git-Tag: v0.11.0~238^2~60 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=c7c6446e3ea37531b67252a452937f3578570a57;p=oweals%2Fgnunet.git use unique 32-bit IDs for DNS requests to avoid random confusions, handle additional and authoritative records as well --- diff --git a/src/arm/test_gnunet_service_arm.c b/src/arm/test_gnunet_service_arm.c index 8b6d09bd9..fd5244ec2 100644 --- a/src/arm/test_gnunet_service_arm.c +++ b/src/arm/test_gnunet_service_arm.c @@ -112,7 +112,7 @@ hostname_resolve_cb (void *cls, if (NULL == addr) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Name not resolved!\n"); + "Failed to resolve our own hostname!\n"); GNUNET_break (0); ret = 3; GNUNET_ARM_request_service_stop (arm, @@ -200,7 +200,7 @@ main (int argc, char *av[]) FPRINTF (stderr, "%s", "Failed to determine my own hostname, testcase not run.\n"); - return 0; + return 77; } if ( (0 == strcmp (hostname, "localhost")) || @@ -210,6 +210,8 @@ main (int argc, char *av[]) /* we cannot use 'localhost' as this would not trigger the resolver service (see resolver_api.c); so in this case, we fall back to (ab)using gnu.org. */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Falling back to `www.gnu.org'\n"); strcpy (hostname, "www.gnu.org"); } @@ -224,7 +226,7 @@ main (int argc, char *av[]) FPRINTF (stderr, "Failed to resolve my hostname `%s', testcase not run.\n", hostname); - return 0; + return 77; } freeaddrinfo (ai); } @@ -240,7 +242,7 @@ main (int argc, char *av[]) FPRINTF (stderr, "Failed to resolve my hostname `%s', testcase not run.\n", hostname); - return 0; + return 77; } } #elif HAVE_GETHOSTBYNAME @@ -253,13 +255,13 @@ main (int argc, char *av[]) FPRINTF (stderr, "Failed to resolve my hostname `%s', testcase not run.\n", hostname); - return 0; + return 77; } } #else FPRINTF (stderr, "libc fails to have resolver function, testcase not run.\n"); - return 0; + return 77; #endif GNUNET_log_setup ("test-gnunet-service-arm", "WARNING", diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c index 90ed746b6..252408466 100644 --- a/src/util/gnunet-service-resolver.c +++ b/src/util/gnunet-service-resolver.c @@ -143,7 +143,7 @@ struct ActiveLookup * Unique request ID of a client if a query for this hostname/record_type * is currently pending, undefined otherwise. */ - uint16_t request_id; + uint32_t client_request_id; /** * Unique DNS request ID of a client if a query for this hostname/record_type @@ -179,11 +179,17 @@ static struct ActiveLookup *lookup_tail; */ static struct GNUNET_DNSSTUB_Context *dnsstub_ctx; +/** + * My domain, to be appended to the hostname to get a FQDN. + */ +static char *my_domain; + /** * How many entries do we have in #cache_head DLL? */ static unsigned int cache_size; + /** * Remove @a entry from cache. * @@ -261,6 +267,28 @@ extract_dns_server (const char* line, } +/** + * Find out if the configuration file line contains a string + * starting with "search ", and if so, return a copy of + * the machine's search domain. + * + * @param line line to parse + * @param line_len number of characters in @a line + * @return NULL if no nameserver is configured in this @a line + */ +static char * +extract_search_domain (const char* line, + size_t line_len) +{ + if (0 == strncmp (line, + "search ", + strlen ("search "))) + return GNUNET_strndup (line + strlen ("search "), + line_len - strlen ("search ")); + return NULL; +} + + /** * Reads the list of nameservers from /etc/resolve.conf * @@ -306,9 +334,16 @@ lookup_dns_servers (char ***server_addrs) dns_server = extract_dns_server (buf + read_offset, line_len); if (NULL != dns_server) + { GNUNET_array_append (*server_addrs, num_dns_servers, dns_server); + } + else if (NULL == my_domain) + { + my_domain = extract_search_domain (buf + read_offset, + line_len); + } read_offset += line_len + 1; } GNUNET_DISK_file_close (fh); @@ -392,7 +427,7 @@ make_reverse_hostname (const void *ip, * * @param record information to transmit * @param record_type requested record type from client - * @param request_id to which request are we responding + * @param client_request_id to which request are we responding * @param client where to send @a record * @return #GNUNET_YES if we sent a reply, * #GNUNET_NO if the record type is not understood or @@ -401,7 +436,7 @@ make_reverse_hostname (const void *ip, static int send_reply (struct GNUNET_DNSPARSER_Record *record, uint16_t record_type, - uint16_t request_id, + uint32_t client_request_id, struct GNUNET_SERVICE_Client *client) { struct GNUNET_RESOLVER_ResponseMessage *msg; @@ -446,7 +481,7 @@ send_reply (struct GNUNET_DNSPARSER_Record *record, env = GNUNET_MQ_msg_extra (msg, payload_len, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - msg->id = request_id; + msg->client_id = client_request_id; GNUNET_memcpy (&msg[1], payload, payload_len); @@ -458,13 +493,13 @@ send_reply (struct GNUNET_DNSPARSER_Record *record, /** * Send message to @a client that we transmitted all - * responses for @a request_id + * responses for @a client_request_id * - * @param request_id to which request are we responding + * @param client_request_id to which request are we responding * @param client where to send @a record */ static void -send_end_msg (uint16_t request_id, +send_end_msg (uint32_t client_request_id, struct GNUNET_SERVICE_Client *client) { struct GNUNET_RESOLVER_ResponseMessage *msg; @@ -474,7 +509,7 @@ send_end_msg (uint16_t request_id, "Sending END message\n"); env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - msg->id = request_id; + msg->client_id = client_request_id; GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); } @@ -518,13 +553,13 @@ remove_expired (struct ResolveCache *rc) * * @param hostname DNS name to resolve * @param record_type desired record type - * @param request_id client's request ID + * @param client_request_id client's request ID * @param client who should get the result? */ static void process_get (const char *hostname, uint16_t record_type, - uint16_t request_id, + uint32_t client_request_id, struct GNUNET_SERVICE_Client *client); @@ -536,13 +571,13 @@ process_get (const char *hostname, * * @param hostname what hostname was to be resolved * @param record_type what type of record was requested - * @param request_id unique identification of the client's request + * @param client_request_id unique identification of the client's request * @param client handle to the client making the request (for sending the reply) */ static int try_cache (const char *hostname, uint16_t record_type, - uint16_t request_id, + uint32_t client_request_id, struct GNUNET_SERVICE_Client *client) { struct ResolveCache *pos; @@ -595,18 +630,18 @@ try_cache (const char *hostname, process_get (hostname, record_type, - request_id, + client_request_id, client); return GNUNET_YES; /* counts as a cache "hit" */ } found |= send_reply (rle->record, record_type, - request_id, + client_request_id, client); } if (GNUNET_NO == found) return GNUNET_NO; /* had records, but none matched! */ - send_end_msg (request_id, + send_end_msg (client_request_id, client); return GNUNET_YES; } @@ -693,14 +728,14 @@ handle_resolve_result (void *cls, GNUNET_DNSPARSER_free_packet (parsed); return; } - if (0 == parsed->num_answers) + if (0 == parsed->num_answers + parsed->num_authority_records + parsed->num_additional_records) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS reply (hostname %s, request ID %u) contains no answers\n", al->hostname, - al->request_id); + (unsigned int) al->client_request_id); GNUNET_DNSPARSER_free_packet (parsed); - send_end_msg (al->request_id, + send_end_msg (al->client_request_id, al->client); free_active_lookup (al); return; @@ -712,7 +747,7 @@ handle_resolve_result (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got reply for hostname %s and request ID %u\n", al->hostname, - al->request_id); + (unsigned int) al->client_request_id); /* add to cache */ for (unsigned int i = 0; i != parsed->num_answers; i++) { @@ -740,6 +775,58 @@ handle_resolve_result (void *cls, rc->records_tail, rle); } + for (unsigned int i = 0; i != parsed->num_authority_records; i++) + { + struct GNUNET_DNSPARSER_Record *record = &parsed->authority_records[i]; + struct RecordListEntry *rle; + + for (rc = cache_head; NULL != rc; rc = rc->next) + if (0 == strcasecmp (rc->hostname, + record->name)) + break; + if (NULL == rc) + { + rc = GNUNET_new (struct ResolveCache); + rc->hostname = GNUNET_strdup (record->name); + GNUNET_CONTAINER_DLL_insert (cache_head, + cache_tail, + rc); + cache_size++; + } + /* TODO: ought to check first if we have this exact record + already in the cache! */ + rle = GNUNET_new (struct RecordListEntry); + rle->record = GNUNET_DNSPARSER_duplicate_record (record); + GNUNET_CONTAINER_DLL_insert (rc->records_head, + rc->records_tail, + rle); + } + for (unsigned int i = 0; i != parsed->num_additional_records; i++) + { + struct GNUNET_DNSPARSER_Record *record = &parsed->additional_records[i]; + struct RecordListEntry *rle; + + for (rc = cache_head; NULL != rc; rc = rc->next) + if (0 == strcasecmp (rc->hostname, + record->name)) + break; + if (NULL == rc) + { + rc = GNUNET_new (struct ResolveCache); + rc->hostname = GNUNET_strdup (record->name); + GNUNET_CONTAINER_DLL_insert (cache_head, + cache_tail, + rc); + cache_size++; + } + /* TODO: ought to check first if we have this exact record + already in the cache! */ + rle = GNUNET_new (struct RecordListEntry); + rle->record = GNUNET_DNSPARSER_duplicate_record (record); + GNUNET_CONTAINER_DLL_insert (rc->records_head, + rc->records_tail, + rle); + } /* see if we need to do the 2nd request for AAAA records */ if ( (GNUNET_DNSPARSER_TYPE_ALL == al->record_type) && (GNUNET_NO == al->did_aaaa) ) @@ -774,11 +861,13 @@ handle_resolve_result (void *cls, if (GNUNET_NO == try_cache (al->hostname, al->record_type, - al->request_id, + al->client_request_id, al->client)) /* cache failed, tell client we could not get an answer */ - send_end_msg (al->request_id, + { + send_end_msg (al->client_request_id, al->client); + } free_active_lookup (al); GNUNET_DNSPARSER_free_packet (parsed); } @@ -798,7 +887,7 @@ handle_resolve_timeout (void *cls) al->timeout_task = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS lookup timeout!\n"); - send_end_msg (al->request_id, + send_end_msg (al->client_request_id, al->client); free_active_lookup (al); } @@ -810,14 +899,14 @@ handle_resolve_timeout (void *cls) * * @param hostname DNS name to resolve * @param record_type record type to locate - * @param request_id client request ID + * @param client_request_id client request ID * @param client handle to the client * @return #GNUNET_OK if the DNS query is now pending */ static int resolve_and_cache (const char* hostname, uint16_t record_type, - uint16_t request_id, + uint32_t client_request_id, struct GNUNET_SERVICE_Client *client) { char *packet_buf; @@ -827,7 +916,8 @@ resolve_and_cache (const char* hostname, uint16_t type; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "resolve_and_cache\n"); + "resolve_and_cache `%s'\n", + hostname); dns_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT16_MAX); @@ -851,7 +941,7 @@ resolve_and_cache (const char* hostname, al = GNUNET_new (struct ActiveLookup); al->hostname = GNUNET_strdup (hostname); al->record_type = record_type; - al->request_id = request_id; + al->client_request_id = client_request_id; al->dns_id = dns_id; al->client = client; al->timeout_task = GNUNET_SCHEDULER_add_delayed (DNS_TIMEOUT, @@ -868,42 +958,68 @@ resolve_and_cache (const char* hostname, lookup_tail, al); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Resolving %s, request_id = %u, dns_id = %u\n", + "Resolving %s, client_request_id = %u, dns_id = %u\n", hostname, - (unsigned int) request_id, + (unsigned int) client_request_id, (unsigned int) dns_id); return GNUNET_OK; } /** - * Process DNS request for @a hostname with request ID @a request_id + * Process DNS request for @a hostname with request ID @a client_request_id * from @a client demanding records of type @a record_type. * * @param hostname DNS name to resolve * @param record_type desired record type - * @param request_id client's request ID + * @param client_request_id client's request ID * @param client who should get the result? */ static void process_get (const char *hostname, uint16_t record_type, - uint16_t request_id, + uint32_t client_request_id, struct GNUNET_SERVICE_Client *client) { + char fqdn[255]; + + if ( (NULL != my_domain) && + (NULL == strchr (hostname, + (unsigned char) '.')) && + (strlen (hostname) + strlen (my_domain) <= 253) ) + { + GNUNET_snprintf (fqdn, + sizeof (fqdn), + "%s.%s", + hostname, + my_domain); + } + else if (strlen (hostname) < 255) + { + GNUNET_snprintf (fqdn, + sizeof (fqdn), + "%s", + hostname); + } + else + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (client); + return; + } if (GNUNET_NO == - try_cache (hostname, + try_cache (fqdn, record_type, - request_id, + client_request_id, client)) { if (GNUNET_OK != - resolve_and_cache (hostname, + resolve_and_cache (fqdn, record_type, - request_id, + client_request_id, client)) { - send_end_msg (request_id, + send_end_msg (client_request_id, client); } } @@ -979,12 +1095,13 @@ handle_get (void *cls, struct GNUNET_SERVICE_Client *client = cls; int direction; int af; - uint16_t request_id; + uint32_t client_request_id; char *hostname; direction = ntohl (msg->direction); af = ntohl (msg->af); - request_id = ntohs (msg->id); + client_request_id = msg->client_id; + GNUNET_SERVICE_client_continue (client); if (GNUNET_NO == direction) { /* IP from hostname */ @@ -995,7 +1112,7 @@ handle_get (void *cls, { process_get (hostname, GNUNET_DNSPARSER_TYPE_ALL, - request_id, + client_request_id, client); break; } @@ -1003,7 +1120,7 @@ handle_get (void *cls, { process_get (hostname, GNUNET_DNSPARSER_TYPE_A, - request_id, + client_request_id, client); break; } @@ -1011,15 +1128,15 @@ handle_get (void *cls, { process_get (hostname, GNUNET_DNSPARSER_TYPE_AAAA, - request_id, + client_request_id, client); break; } default: { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "got invalid af: %d\n", - af); + "got invalid af: %d\n", + af); GNUNET_assert (0); } } @@ -1031,11 +1148,10 @@ handle_get (void *cls, af); process_get (hostname, GNUNET_DNSPARSER_TYPE_PTR, - request_id, + client_request_id, client); } GNUNET_free_non_null (hostname); - GNUNET_SERVICE_client_continue (client); } diff --git a/src/util/resolver.h b/src/util/resolver.h index 07851d052..54a1cf5fd 100644 --- a/src/util/resolver.h +++ b/src/util/resolver.h @@ -41,7 +41,7 @@ GNUNET_NETWORK_STRUCT_BEGIN struct GNUNET_RESOLVER_GetMessage { /** - * Type: GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST + * Type: #GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST */ struct GNUNET_MessageHeader header; @@ -60,7 +60,7 @@ struct GNUNET_RESOLVER_GetMessage * identifies the request and is contained in the response message. The * client has to match response to request by this identifier. */ - uint16_t id GNUNET_PACKED; + uint32_t client_id GNUNET_PACKED; /* followed by 0-terminated string for A/AAAA-lookup or by 'struct in_addr' / 'struct in6_addr' for reverse lookup */ @@ -71,15 +71,15 @@ struct GNUNET_RESOLVER_GetMessage struct GNUNET_RESOLVER_ResponseMessage { /** - * Type: GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE + * Type: #GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE */ struct GNUNET_MessageHeader header; /** - * identifies the request this message responds to. The client - * has to match response to request by this identifier. - */ - uint16_t id GNUNET_PACKED; + * identifies the request this message responds to. The client + * has to match response to request by this identifier. + */ + uint32_t client_id GNUNET_PACKED; /* followed by 0-terminated string for response to a reverse lookup * or by 'struct in_addr' / 'struct in6_addr' for response to diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c index 8a054327b..871eeb4bf 100644 --- a/src/util/resolver_api.c +++ b/src/util/resolver_api.c @@ -68,10 +68,10 @@ static struct GNUNET_RESOLVER_RequestHandle *req_head; */ static struct GNUNET_RESOLVER_RequestHandle *req_tail; -///** -// * ID of the last request we sent to the service -// */ -//static uint16_t last_request_id; +/** + * ID of the last request we sent to the service + */ +static uint32_t last_request_id; /** * How long should we wait to reconnect? @@ -445,7 +445,7 @@ process_requests () GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); msg->direction = htonl (rh->direction); msg->af = htonl (rh->af); - msg->id = htons (rh->id); + msg->client_id = rh->id; GNUNET_memcpy (&msg[1], &rh[1], rh->data_len); @@ -491,11 +491,11 @@ handle_response (void *cls, struct GNUNET_RESOLVER_RequestHandle *rh = req_head; uint16_t size; char *nret; - uint16_t request_id = msg->id; + uint32_t client_request_id = msg->client_id; for (; rh != NULL; rh = rh->next) { - if (rh->id == request_id) + if (rh->id == client_request_id) break; } @@ -911,14 +911,6 @@ handle_lookup_timeout (void *cls) } -static uint16_t -get_request_id () -{ - return (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, - UINT16_MAX); -} - - /** * Convert a string to one or more IP addresses. * @@ -953,8 +945,7 @@ GNUNET_RESOLVER_ip_get (const char *hostname, hostname); rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen); rh->af = af; - //rh->id = ++last_request_id; - rh->id = get_request_id (); + rh->id = ++last_request_id; rh->addr_callback = callback; rh->cls = callback_cls; GNUNET_memcpy (&rh[1], @@ -1101,8 +1092,7 @@ GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, rh->name_callback = callback; rh->cls = cls; rh->af = sa->sa_family; - //rh->id = ++last_request_id; - rh->id = get_request_id (); + rh->id = ++last_request_id; rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); GNUNET_memcpy (&rh[1], ip,