2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @file gns/gnunet-service-gns.c
24 * @brief GNUnet GNS service
25 * @author Martin Schanzenbach
28 #include "gnunet_util_lib.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_dns_service.h"
31 #include "gnunet_dnsparser_lib.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_gns_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "block_gns.h"
38 #include "gnunet-service-gns_resolver.h"
39 #include "gnunet-service-gns_interceptor.h"
41 /* FIXME move to proper header in include */
42 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
43 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
44 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
45 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
46 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH 27
47 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28
51 * Handle to a shorten operation from api
53 struct ClientShortenHandle
57 struct ClientShortenHandle *next;
60 struct ClientShortenHandle *prev;
62 /* the requesting client that */
63 struct GNUNET_SERVER_Client *client;
69 enum GNUNET_GNS_RecordType type;
72 char name[MAX_DNS_NAME_LENGTH];
74 /* name of private zone (relative to root) */
75 char private_zone_id[MAX_DNS_NAME_LENGTH];
77 /* name of shorten zone (relative to root) */
78 char shorten_zone_id[MAX_DNS_NAME_LENGTH];
81 struct GNUNET_CRYPTO_ShortHashCode root_zone;
84 struct GNUNET_CRYPTO_ShortHashCode private_zone;
87 struct GNUNET_CRYPTO_ShortHashCode shorten_zone;
89 /* Namestore lookup task */
90 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
96 * Handle to a get auhtority operation from api
98 struct ClientGetAuthHandle
100 /* the requesting client that */
101 struct GNUNET_SERVER_Client *client;
106 /* name to lookup authority */
113 * Handle to a lookup operation from api
115 struct ClientLookupHandle
118 /* the requesting client that */
119 struct GNUNET_SERVER_Client *client;
121 /* The zone we look up in */
122 struct GNUNET_CRYPTO_ShortHashCode zone;
124 /* Do we only want to lookup from local cache? */
131 enum GNUNET_GNS_RecordType type;
133 /* optional zone private key used for shorten */
134 struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key;
136 /* the name to look up */
137 char* name; //Needed?
141 * Our handle to the DHT
143 static struct GNUNET_DHT_Handle *dht_handle;
146 * Our zone's private key
148 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
151 * Our handle to the namestore service
152 * FIXME maybe need a second handle for iteration
154 struct GNUNET_NAMESTORE_Handle *namestore_handle;
157 * Handle to iterate over our authoritative zone in namestore
159 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
162 * The configuration the GNS service is running with
164 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
167 * Our notification context.
169 static struct GNUNET_SERVER_NotificationContext *nc;
174 struct GNUNET_CRYPTO_ShortHashCode zone_hash;
177 * Useful for zone update for DHT put
179 static int num_public_records;
182 * update interval in seconds
184 static unsigned long long max_record_put_interval;
186 static struct GNUNET_TIME_Relative dht_max_update_interval;
188 /* dht update interval FIXME define? */
189 static struct GNUNET_TIME_Relative record_put_interval;
191 /* zone update task */
192 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
194 /* automatic pkey import for name shortening */
195 static int auto_import_pkey;
198 static struct GNUNET_TIME_Relative default_lookup_timeout;
201 static int v6_enabled;
204 static int v4_enabled;
206 /* Shorten DLL for cancelling NS requests */
207 static struct ClientShortenHandle *csh_head;
209 /* Shorten DLL for cancelling NS requests */
210 static struct ClientShortenHandle *csh_tail;
212 /* Statistics handle */
213 static struct GNUNET_STATISTICS_Handle *statistics;
216 * Send shorten response back to client
218 * @param cls the closure containing a client shorten handle
219 * @param name the shortened name result or NULL if cannot be shortened
222 send_shorten_response(void* cls, const char* name);
229 on_resolver_cleanup(void)
231 if (NULL != namestore_iter)
232 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
233 GNUNET_NAMESTORE_disconnect(namestore_handle);
234 GNUNET_DHT_disconnect(dht_handle);
238 * Task run during shutdown.
244 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
246 struct ClientShortenHandle *csh_tmp = csh_head;
248 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
251 while (csh_tmp != NULL)
253 GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh_tmp);
254 send_shorten_response (csh_tmp, csh_tmp->name);
257 GNUNET_SERVER_notification_context_destroy (nc);
259 gns_interceptor_stop();
260 gns_resolver_cleanup(&on_resolver_cleanup);
261 /* Kill zone task for it may make the scheduler hang */
262 if (zone_update_taskid != GNUNET_SCHEDULER_NO_TASK)
263 GNUNET_SCHEDULER_cancel(zone_update_taskid);
268 * Method called periodicattluy that triggers
269 * iteration over root zone
272 * @param tc task context
275 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
277 zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
278 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
282 * Continuation for DHT put
285 * @param success GNUNET_OK if the PUT was transmitted,
286 * GNUNET_NO on timeout,
287 * GNUNET_SYSERR on disconnect from service
288 * after the PUT message was transmitted
289 * (so we don't know if it was received or not)
292 record_dht_put(void *cls, int success)
294 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
299 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
302 * Function used to put all records successively into the DHT.
304 * @param cls the closure (NULL)
305 * @param key the public key of the authority (ours)
306 * @param expiration lifetime of the namestore entry
307 * @param name the name of the records
308 * @param rd_count the number of records in data
309 * @param rd the record data
310 * @param signature the signature for the record data
313 put_gns_record(void *cls,
314 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
315 struct GNUNET_TIME_Absolute expiration,
317 unsigned int rd_count,
318 const struct GNUNET_NAMESTORE_RecordData *rd,
319 const struct GNUNET_CRYPTO_RsaSignature *signature)
322 struct GNSNameRecordBlock *nrb;
323 struct GNUNET_CRYPTO_ShortHashCode name_hash;
324 struct GNUNET_CRYPTO_ShortHashCode zhash;
325 struct GNUNET_HashCode xor_hash;
326 struct GNUNET_HashCode name_hash_double;
327 struct GNUNET_HashCode zone_hash_double;
328 uint32_t rd_payload_length;
329 char* nrb_data = NULL;
335 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
336 "Zone iteration finished. Rescheduling put in %llus\n",
337 (unsigned long long) dht_max_update_interval.rel_value / 1000LL);
338 namestore_iter = NULL;
339 zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_max_update_interval,
340 &update_zone_dht_start,
342 GNUNET_STATISTICS_update (statistics,
343 "Number of zone iterations", 1, GNUNET_NO);
347 namelen = strlen(name) + 1;
349 if (signature == NULL)
351 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
352 "No signature for %s record data provided! Skipping...\n",
354 zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
360 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
361 "Putting records for %s into the DHT\n", name);
363 rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
365 nrb = GNUNET_malloc(rd_payload_length + namelen
366 + sizeof(struct GNSNameRecordBlock));
368 nrb->signature = *signature;
370 nrb->public_key = *key;
372 nrb->rd_count = htonl(rd_count);
374 memcpy(&nrb[1], name, namelen);
376 nrb_data = (char*)&nrb[1];
379 rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen;
381 if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
386 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
387 "Record serialization failed! Skipping...\n");
389 zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
396 * calculate DHT key: H(name) xor H(pubkey)
398 GNUNET_CRYPTO_short_hash(key,
399 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
401 GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
402 GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
403 GNUNET_CRYPTO_short_hash_double (&zhash, &zone_hash_double);
404 GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash);
406 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
407 "zone identity: %s\n", GNUNET_h2s (&zone_hash_double));
409 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
410 "putting records for %s under key: %s with size %d\n",
411 name, GNUNET_h2s (&xor_hash), rd_payload_length);
413 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
414 "DHT req to %d\n", DHT_OPERATION_TIMEOUT.rel_value);
416 GNUNET_STATISTICS_update (statistics,
417 "Record data set put into DHT", 1, GNUNET_NO);
419 /* FIXME: keep return value to possibly cancel? */
420 GNUNET_DHT_put (dht_handle, &xor_hash,
421 DHT_GNS_REPLICATION_LEVEL,
423 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
427 DHT_OPERATION_TIMEOUT,
429 NULL); //cls for cont
431 num_public_records++;
434 * Reschedule periodic put
436 zone_update_taskid = GNUNET_SCHEDULER_add_delayed (record_put_interval,
437 &update_zone_dht_next,
445 * Periodically iterate over our zone and store everything in dht
448 * @param tc task context
451 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
453 unsigned long long interval = 0;
455 zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
457 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling DHT zone update!\n");
458 if (0 == num_public_records)
461 * If no records are known (startup) or none present
462 * we can safely set the interval to 1s
464 record_put_interval = GNUNET_TIME_relative_multiply(
465 GNUNET_TIME_UNIT_SECONDS,
467 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
468 "No records in db. Adjusted record put interval to 1s\n");
469 GNUNET_STATISTICS_set (statistics,
470 "Current PUT interval (sec)", 1,
475 interval = max_record_put_interval/num_public_records;
478 record_put_interval = GNUNET_TIME_relative_multiply(
479 GNUNET_TIME_UNIT_SECONDS,
481 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
482 "Adjusted DHT update interval to %ds!\n",
484 GNUNET_STATISTICS_set (statistics,
485 "Current PUT interval (sec)", interval,
489 /* start counting again */
490 num_public_records = 0;
491 namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
493 GNUNET_NAMESTORE_RF_AUTHORITY,
494 GNUNET_NAMESTORE_RF_PRIVATE,
499 /* END DHT ZONE PROPAGATION */
502 * Send shorten response back to client
504 * @param cls the closure containing a client shorten handle
505 * @param name the shortened name result or NULL if cannot be shortened
508 send_shorten_response(void* cls, const char* name)
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
511 "SHORTEN_RESULT", name);
512 struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
513 struct ClientShortenHandle *csh = (struct ClientShortenHandle *)cls;
520 GNUNET_STATISTICS_update (statistics,
521 "Name shorten results", 1, GNUNET_NO);
523 rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage)
526 rmsg->id = csh->unique_id;
527 rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
529 htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
532 strcpy((char*)&rmsg[1], name);
534 GNUNET_SERVER_notification_context_unicast (nc, csh->client,
535 (const struct GNUNET_MessageHeader *) rmsg,
537 GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
539 if (NULL != csh->namestore_task)
540 GNUNET_NAMESTORE_cancel (csh->namestore_task);
549 * Lookup the zone infos and shorten name
551 * @param cls the client shorten handle
552 * @param key key of the zone
553 * @param expiration expiration of record
554 * @param name name found or null if no result
555 * @param rd_count number of records found
556 * @param rd record data
561 process_shorten_in_private_zone_lookup (void *cls,
562 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
563 struct GNUNET_TIME_Absolute expiration,
565 unsigned int rd_count,
566 const struct GNUNET_NAMESTORE_RecordData *rd,
567 const struct GNUNET_CRYPTO_RsaSignature *signature)
569 struct ClientShortenHandle *csh = cls;
570 csh->namestore_task = NULL;
571 struct GNUNET_CRYPTO_ShortHashCode *szone = &csh->shorten_zone;
572 struct GNUNET_CRYPTO_ShortHashCode *pzone = &csh->private_zone;
574 if (0 == strcmp (csh->private_zone_id, ""))
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "No shorten zone in private zone!\n");
582 strcpy (csh->shorten_zone_id, "");
589 GNUNET_assert (rd_count == 1);
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592 "Shorten zone %s found in private zone %s\n",
593 name, csh->private_zone_id);
595 sprintf (csh->shorten_zone_id, "%s.%s", name, csh->private_zone_id);
598 GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
600 gns_resolver_shorten_name (&csh->root_zone,
604 csh->private_zone_id,
605 csh->shorten_zone_id,
606 &send_shorten_response, csh);
612 * Lookup the zone infos and shorten name
614 * @param cls the shorten handle
615 * @param key key of the zone
616 * @param expiration expiration of record
617 * @param name name found or null if no result
618 * @param rd_count number of records found
619 * @param rd record data
624 process_shorten_in_root_zone_lookup (void *cls,
625 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
626 struct GNUNET_TIME_Absolute expiration,
628 unsigned int rd_count,
629 const struct GNUNET_NAMESTORE_RecordData *rd,
630 const struct GNUNET_CRYPTO_RsaSignature *signature)
632 struct ClientShortenHandle *csh = cls;
633 csh->namestore_task = NULL;
634 struct GNUNET_CRYPTO_ShortHashCode *szone = &csh->shorten_zone;
635 struct GNUNET_CRYPTO_ShortHashCode *pzone = &csh->private_zone;
637 if (0 == strcmp (csh->private_zone_id, ""))
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643 "No shorten zone in zone and no private zone!\n");
645 strcpy (csh->shorten_zone_id, "");
647 GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
650 gns_resolver_shorten_name (&csh->root_zone,
654 csh->private_zone_id,
655 csh->shorten_zone_id,
656 &send_shorten_response, csh);
660 GNUNET_assert (rd_count == 1);
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Private zone %s found in root zone\n", name);
665 strcpy (csh->private_zone_id, name);
667 csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
670 &process_shorten_in_private_zone_lookup,
676 * Lookup the zone infos and shorten name
678 * @param cls the shorten handle
679 * @param key key of the zone
680 * @param expiration expiration of record
681 * @param name name found or null if no result
682 * @param rd_count number of records found
683 * @param rd record data
688 process_private_in_root_zone_lookup (void *cls,
689 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
690 struct GNUNET_TIME_Absolute expiration,
692 unsigned int rd_count,
693 const struct GNUNET_NAMESTORE_RecordData *rd,
694 const struct GNUNET_CRYPTO_RsaSignature *signature)
696 struct ClientShortenHandle *csh = cls;
697 csh->namestore_task = NULL;
701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702 "No private zone in root zone\n");
704 strcpy (csh->private_zone_id, "");
706 csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
709 &process_shorten_in_root_zone_lookup,
714 GNUNET_assert (rd_count == 1);
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "Private zone %s found in root zone\n", name);
719 strcpy (csh->private_zone_id, name);
721 csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
724 &process_shorten_in_private_zone_lookup,
729 * Lookup the zone infos and shorten name
731 * @param csh the shorten handle
735 start_shorten_name (struct ClientShortenHandle *csh)
737 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
738 "Looking for private zone name in root zone\n");
740 csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
743 &process_private_in_root_zone_lookup,
749 * Handle a shorten message from the api
751 * @param cls the closure
752 * @param client the client
753 * @param message the message
755 static void handle_shorten (void *cls,
756 struct GNUNET_SERVER_Client * client,
757 const struct GNUNET_MessageHeader * message)
759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
762 struct ClientShortenHandle *csh;
763 char name[MAX_DNS_NAME_LENGTH];
764 char* nameptr = name;
766 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
769 GNUNET_SERVER_receive_done (client, GNUNET_OK);
774 struct GNUNET_GNS_ClientShortenMessage *sh_msg =
775 (struct GNUNET_GNS_ClientShortenMessage *) message;
777 msg_size = ntohs(message->size);
779 if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
782 GNUNET_SERVER_receive_done (client, GNUNET_OK);
786 csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
787 csh->client = client;
788 csh->unique_id = sh_msg->id;
790 GNUNET_CONTAINER_DLL_insert (csh_head, csh_tail, csh);
792 GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr);
794 if (strlen (name) < strlen(GNUNET_GNS_TLD)) {
795 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
796 "SHORTEN: %s is too short", name);
797 send_shorten_response(csh, name);
801 if (strlen (name) > MAX_DNS_NAME_LENGTH) {
802 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
803 "SHORTEN: %s is too long", name);
804 send_shorten_response(csh, name);
808 if (!is_gnunet_tld(name) && !is_zkey_tld(name))
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "%s is not our domain. Returning\n", name);
812 send_shorten_response(csh, name);
816 csh->shorten_zone = sh_msg->shorten_zone;
817 csh->private_zone = sh_msg->private_zone;
819 strcpy (csh->name, name);
821 GNUNET_SERVER_notification_context_add (nc, client);
823 if (1 == ntohl(sh_msg->use_default_zone))
824 csh->root_zone = zone_hash; //Default zone
826 csh->root_zone = sh_msg->zone;
828 start_shorten_name (csh);
830 GNUNET_STATISTICS_update (statistics,
831 "Name shorten attempts", 1, GNUNET_NO);
837 * Send get authority response back to client
839 * @param cls the closure containing a client get auth handle
840 * @param name the shortened name result or NULL if cannot be shortened
843 send_get_auth_response(void *cls, const char* name)
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
846 "GET_AUTH_RESULT", name);
847 struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
848 struct ClientGetAuthHandle *cah = (struct ClientGetAuthHandle *)cls;
852 GNUNET_STATISTICS_update (statistics,
853 "Authorities resolved", 1, GNUNET_NO);
861 rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage)
864 rmsg->id = cah->unique_id;
865 rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
867 htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
870 strcpy((char*)&rmsg[1], name);
872 GNUNET_SERVER_notification_context_unicast (nc, cah->client,
873 (const struct GNUNET_MessageHeader *) rmsg,
875 GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
878 GNUNET_free_non_null(cah->name);
887 * Handle a get authority message from the api
889 * @param cls the closure
890 * @param client the client
891 * @param message the message
893 static void handle_get_authority(void *cls,
894 struct GNUNET_SERVER_Client * client,
895 const struct GNUNET_MessageHeader * message)
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH");
900 struct ClientGetAuthHandle *cah;
901 char name[MAX_DNS_NAME_LENGTH];
902 char* nameptr = name;
905 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
908 GNUNET_SERVER_receive_done (client, GNUNET_OK);
912 GNUNET_SERVER_notification_context_add (nc, client);
914 struct GNUNET_GNS_ClientGetAuthMessage *sh_msg =
915 (struct GNUNET_GNS_ClientGetAuthMessage *) message;
917 msg_size = ntohs(message->size);
919 if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
922 GNUNET_SERVER_receive_done (client, GNUNET_OK);
926 GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr);
929 cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
930 cah->client = client;
931 cah->unique_id = sh_msg->id;
933 if (strlen(name) < strlen(GNUNET_GNS_TLD))
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936 "GET_AUTH: %s is too short. Returning\n", name);
938 send_get_auth_response(cah, name);
942 if (strlen (name) > MAX_DNS_NAME_LENGTH) {
943 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
944 "GET_AUTH: %s is too long", name);
946 send_get_auth_response(cah, name);
950 if (strcmp(name+strlen(name)-strlen(GNUNET_GNS_TLD),
951 GNUNET_GNS_TLD) != 0)
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "GET_AUTH: %s is not our domain. Returning\n", name);
956 send_get_auth_response(cah, name);
960 if (strcmp(name, GNUNET_GNS_TLD) == 0)
962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963 "GET_AUTH: %s is us. Returning\n", name);
965 send_get_auth_response(cah, name);
969 cah->name = GNUNET_malloc(strlen(name)
970 - strlen(GNUNET_GNS_TLD) + 1);
972 strlen(name)-strlen(GNUNET_GNS_TLD) + 1);
973 memcpy(cah->name, name,
974 strlen(name)-strlen(GNUNET_GNS_TLD));
976 /* Start delegation resolution in our namestore */
977 gns_resolver_get_authority(zone_hash, zone_hash, name, &send_get_auth_response, cah);
979 GNUNET_STATISTICS_update (statistics,
980 "Authority lookup attempts", 1, GNUNET_NO);
986 * Reply to client with the result from our lookup.
988 * @param cls the closure (our client lookup handle)
989 * @param rd_count the number of records
990 * @param rd the record data
993 send_lookup_response(void* cls,
995 const struct GNUNET_NAMESTORE_RecordData *rd)
997 struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
998 struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
1002 "LOOKUP_RESULT", rd_count);
1004 len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1005 rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
1007 rmsg->id = clh->unique_id;
1008 rmsg->rd_count = htonl(rd_count);
1009 rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
1011 htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
1013 GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
1015 GNUNET_SERVER_notification_context_unicast (nc, clh->client,
1016 (const struct GNUNET_MessageHeader *) rmsg,
1018 GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
1021 GNUNET_free(clh->name);
1023 if (NULL != clh->shorten_key)
1024 GNUNET_free(clh->shorten_key);
1028 GNUNET_STATISTICS_update (statistics,
1029 "Completed lookups", 1, GNUNET_NO);
1033 GNUNET_STATISTICS_update (statistics,
1034 "Records resolved", rd_count, GNUNET_NO);
1041 * Handle lookup requests from client
1043 * @param cls the closure
1044 * @param client the client
1045 * @param message the message
1048 handle_lookup(void *cls,
1049 struct GNUNET_SERVER_Client * client,
1050 const struct GNUNET_MessageHeader * message)
1052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
1054 size_t msg_size = 0;
1056 char name[MAX_DNS_NAME_LENGTH];
1057 struct ClientLookupHandle *clh;
1058 char* nameptr = name;
1060 struct GNUNET_CRYPTO_RsaPrivateKey *key;
1061 struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pkey;
1064 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage))
1066 GNUNET_break_op (0);
1067 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1071 GNUNET_SERVER_notification_context_add (nc, client);
1073 struct GNUNET_GNS_ClientLookupMessage *sh_msg =
1074 (struct GNUNET_GNS_ClientLookupMessage *) message;
1076 msg_size = ntohs(message->size);
1078 if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
1080 GNUNET_break_op (0);
1081 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1085 if (1 == ntohl(sh_msg->have_key))
1087 pkey = (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *)&sh_msg[1];
1088 tmp_pkey = (char*)&sh_msg[1];
1089 key = GNUNET_CRYPTO_rsa_decode_key (tmp_pkey, ntohs(pkey->len));
1090 GNUNET_STRINGS_utf8_tolower(&tmp_pkey[ntohs(pkey->len)], &nameptr);
1095 GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr);
1098 namelen = strlen(name)+1;
1099 clh = GNUNET_malloc (sizeof (struct ClientLookupHandle));
1100 memset (clh, 0, sizeof (struct ClientLookupHandle));
1101 clh->client = client;
1102 clh->name = GNUNET_malloc(namelen);
1103 strcpy(clh->name, name);
1104 clh->unique_id = sh_msg->id;
1105 clh->type = ntohl(sh_msg->type);
1106 clh->shorten_key = key;
1108 only_cached = ntohl(sh_msg->only_cached);
1110 if (strlen (name) > MAX_DNS_NAME_LENGTH) {
1111 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1112 "LOOKUP: %s is too long", name);
1114 send_lookup_response(clh, 0, NULL);
1118 if ((clh->type == GNUNET_GNS_RECORD_A) &&
1119 (GNUNET_OK != v4_enabled))
1121 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1122 "LOOKUP: Query for A record but AF_INET not supported!");
1124 send_lookup_response(clh, 0, NULL);
1128 if ((clh->type == GNUNET_GNS_RECORD_AAAA) &&
1129 (GNUNET_OK != v6_enabled))
1131 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1132 "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
1134 send_lookup_response(clh, 0, NULL);
1138 if (1 == ntohl(sh_msg->use_default_zone))
1139 clh->zone = zone_hash; //Default zone
1141 clh->zone = sh_msg->zone;
1143 if (GNUNET_YES == auto_import_pkey)
1145 gns_resolver_lookup_record (clh->zone, clh->zone, clh->type, clh->name,
1147 default_lookup_timeout,
1149 &send_lookup_response, clh);
1153 gns_resolver_lookup_record (clh->zone, clh->zone, clh->type, name,
1155 default_lookup_timeout,
1157 &send_lookup_response, clh);
1160 GNUNET_STATISTICS_update (statistics,
1161 "Record lookup attempts", 1, GNUNET_NO);
1165 * Test if the given AF is supported by this system.
1168 * @return GNUNET_OK if the AF is supported
1175 s = socket (af, SOCK_STREAM, 0);
1178 if (EAFNOSUPPORT == errno)
1180 fprintf (stderr, "Failed to create test socket: %s\n", STRERROR (errno));
1181 return GNUNET_SYSERR;
1188 * Process GNS requests.
1190 * @param cls closure)
1191 * @param server the initialized server
1192 * @param c configuration to use
1195 run (void *cls, struct GNUNET_SERVER_Handle *server,
1196 const struct GNUNET_CONFIGURATION_Handle *c)
1199 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
1202 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
1203 unsigned long long max_parallel_bg_queries = 0;
1204 unsigned long long default_lookup_timeout_secs = 0;
1205 int ignore_pending = GNUNET_NO;
1207 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1208 {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
1209 {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
1210 {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
1215 v6_enabled = test_af (AF_INET6);
1216 v4_enabled = test_af (AF_INET);
1218 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns",
1219 "ZONEKEY", &keyfile))
1221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1222 "No private key for root zone specified!\n");
1223 GNUNET_SCHEDULER_shutdown ();
1227 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1228 "Using keyfile %s for root zone.\n", keyfile);
1230 zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1231 GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
1233 GNUNET_CRYPTO_short_hash(&pkey,
1234 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1236 GNUNET_free(keyfile);
1239 * handle to our local namestore
1241 namestore_handle = GNUNET_NAMESTORE_connect(c);
1243 if (NULL == namestore_handle)
1245 //FIXME do error handling;
1246 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1247 "Failed to connect to the namestore!\n");
1248 GNUNET_SCHEDULER_shutdown ();
1254 auto_import_pkey = GNUNET_NO;
1257 GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1258 "AUTO_IMPORT_PKEY"))
1260 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1261 "Automatic PKEY import is enabled.\n");
1262 auto_import_pkey = GNUNET_YES;
1266 dht_max_update_interval.rel_value = GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL; // yuck
1269 GNUNET_CONFIGURATION_get_value_time (c, "gns",
1270 "ZONE_PUT_INTERVAL",
1271 &dht_max_update_interval))
1273 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1274 "DHT zone update interval: %llu\n",
1275 (unsigned long long) dht_max_update_interval.rel_value);
1278 max_record_put_interval = 1;
1281 GNUNET_CONFIGURATION_get_value_number (c, "gns",
1282 "RECORD_PUT_INTERVAL",
1283 &max_record_put_interval))
1285 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1286 "Record put interval: %llu\n",
1287 max_record_put_interval);
1291 GNUNET_CONFIGURATION_get_value_number (c, "gns",
1292 "MAX_PARALLEL_BACKGROUND_QUERIES",
1293 &max_parallel_bg_queries))
1295 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1296 "Number of allowed parallel background queries: %llu\n",
1297 max_parallel_bg_queries);
1301 GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1302 "AUTO_IMPORT_CONFIRMATION_REQ"))
1304 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1305 "Auto import requires user confirmation\n");
1306 ignore_pending = GNUNET_YES;
1310 GNUNET_CONFIGURATION_get_value_number(c, "gns",
1311 "DEFAULT_LOOKUP_TIMEOUT",
1312 &default_lookup_timeout_secs))
1314 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1315 "Default lookup timeout: %llus\n", default_lookup_timeout_secs);
1316 default_lookup_timeout = GNUNET_TIME_relative_multiply(
1317 GNUNET_TIME_UNIT_SECONDS,
1318 default_lookup_timeout_secs);
1324 dht_handle = GNUNET_DHT_connect(c,
1325 //max_parallel_bg_queries); //FIXME get ht_len from cfg
1328 if (NULL == dht_handle)
1330 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1333 if (gns_resolver_init(namestore_handle, dht_handle, zone_hash, c,
1334 max_parallel_bg_queries,
1338 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1339 "Unable to initialize resolver!\n");
1340 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1345 GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "HIJACK_DNS"))
1347 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1348 "DNS hijacking enabled... connecting to service.\n");
1350 if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR)
1352 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1353 "Failed to enable the dns interceptor!\n");
1358 * Schedule periodic put
1360 * We have roughly an hour for all records;
1362 record_put_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1364 zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1366 GNUNET_SERVER_add_handlers (server, handlers);
1369 //GNUNET_SERVER_disconnect_notify (server,
1370 // &client_disconnect_notification,
1373 statistics = GNUNET_STATISTICS_create ("gns", c);
1375 nc = GNUNET_SERVER_notification_context_create (server, 1);
1377 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1383 * The main function for the GNS service.
1385 * @param argc number of arguments from the command line
1386 * @param argv command line arguments
1387 * @return 0 ok, 1 on error
1390 main (int argc, char *const *argv)
1396 GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1401 /* end of gnunet-service-gns.c */