aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2012-03-14 13:16:35 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2012-03-14 13:16:35 +0000
commit763feb7960b78a14971a6f36b73ceb92ff9b3ad4 (patch)
tree47ebecb1668b54bca366b4c0a5b7bfa34b419533 /src
parentd09c4cbf182c5fb83c2bf4b1929a959db4438860 (diff)
downloadgnunet-763feb7960b78a14971a6f36b73ceb92ff9b3ad4.tar.gz
gnunet-763feb7960b78a14971a6f36b73ceb92ff9b3ad4.zip
-large cleanup and bugfixes
Diffstat (limited to 'src')
-rw-r--r--src/gns/Makefile.am20
-rw-r--r--src/gns/gns.h2
-rw-r--r--src/gns/gnunet-service-gns.c2180
-rw-r--r--src/gns/gnunet-service-gns_interceptor.c327
-rw-r--r--src/gns/gnunet-service-gns_interceptor.h18
-rw-r--r--src/gns/gnunet-service-gns_resolver.c1712
-rw-r--r--src/gns/gnunet-service-gns_resolver.h226
-rw-r--r--src/gns/test_gns_dht_shorten.c500
-rw-r--r--src/gns/test_gns_simple_shorten.c19
9 files changed, 2331 insertions, 2673 deletions
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index 866df1d88..679991fe1 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -28,7 +28,6 @@ bin_PROGRAMS = \
28 28
29check_PROGRAMS = \ 29check_PROGRAMS = \
30 test_gns_simple_shorten \ 30 test_gns_simple_shorten \
31 test_gns_dht_shorten \
32 test_gns_simple_get_authority \ 31 test_gns_simple_get_authority \
33 test_gns_simple_lookup \ 32 test_gns_simple_lookup \
34 test_gns_simple_delegated_lookup \ 33 test_gns_simple_delegated_lookup \
@@ -108,21 +107,6 @@ test_gns_simple_shorten_DEPENDENCIES = \
108 $(top_builddir)/src/gns/libgnunetgns.la \ 107 $(top_builddir)/src/gns/libgnunetgns.la \
109 $(top_builddir)/src/testing/libgnunettesting.la 108 $(top_builddir)/src/testing/libgnunettesting.la
110 109
111test_gns_dht_shorten_SOURCES = \
112 test_gns_dht_shorten.c
113test_gns_dht_shorten_LDADD = \
114 $(top_builddir)/src/util/libgnunetutil.la \
115 $(top_builddir)/src/namestore/libgnunetnamestore.la \
116 $(top_builddir)/src/gns/libgnunetgns.la \
117 $(top_builddir)/src/dht/libgnunetdht.la \
118 $(top_builddir)/src/testing/libgnunettesting.la
119test_gns_dht_shorten_DEPENDENCIES = \
120 $(top_builddir)/src/util/libgnunetutil.la \
121 $(top_builddir)/src/namestore/libgnunetnamestore.la \
122 $(top_builddir)/src/gns/libgnunetgns.la \
123 $(top_builddir)/src/dht/libgnunetdht.la \
124 $(top_builddir)/src/testing/libgnunettesting.la
125
126test_gns_simple_get_authority_SOURCES = \ 110test_gns_simple_get_authority_SOURCES = \
127 test_gns_simple_get_authority.c 111 test_gns_simple_get_authority.c
128test_gns_simple_get_authority_LDADD = \ 112test_gns_simple_get_authority_LDADD = \
@@ -148,7 +132,9 @@ gnunet_gns_DEPENDENCIES = \
148 libgnunetgns.la 132 libgnunetgns.la
149 133
150gnunet_service_gns_SOURCES = \ 134gnunet_service_gns_SOURCES = \
151 gnunet-service-gns.c 135 gnunet-service-gns.c \
136 gnunet-service-gns_resolver.c \
137 gnunet-service-gns_interceptor.c
152gnunet_service_gns_LDADD = \ 138gnunet_service_gns_LDADD = \
153 $(top_builddir)/src/tun/libgnunettun.la \ 139 $(top_builddir)/src/tun/libgnunettun.la \
154 $(top_builddir)/src/mesh/libgnunetmesh.la \ 140 $(top_builddir)/src/mesh/libgnunetmesh.la \
diff --git a/src/gns/gns.h b/src/gns/gns.h
index aad36ebfe..31730f8ac 100644
--- a/src/gns/gns.h
+++ b/src/gns/gns.h
@@ -28,6 +28,8 @@
28#ifndef GNS_H 28#ifndef GNS_H
29#define GNS_H 29#define GNS_H
30 30
31#define GNUNET_GNS_TLD "gnunet"
32
31GNUNET_NETWORK_STRUCT_BEGIN 33GNUNET_NETWORK_STRUCT_BEGIN
32 34
33/** 35/**
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index ea9afcb4c..0d33fad81 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -38,11 +38,8 @@
38#include "gnunet_gns_service.h" 38#include "gnunet_gns_service.h"
39#include "block_gns.h" 39#include "block_gns.h"
40#include "gns.h" 40#include "gns.h"
41 41#include "gnunet-service-gns_resolver.h"
42#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) 42#include "gnunet-service-gns_interceptor.h"
43#define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44#define DHT_GNS_REPLICATION_LEVEL 5
45#define MAX_DNS_LABEL_LENGTH 63
46 43
47/* FIXME move to proper header in include */ 44/* FIXME move to proper header in include */
48#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23 45#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
@@ -53,113 +50,6 @@
53#define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28 50#define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28
54 51
55 52
56struct AuthorityChain
57{
58 struct AuthorityChain *prev;
59
60 struct AuthorityChain *next;
61
62 GNUNET_HashCode zone;
63
64 /* (local) name of the authority */
65 char* name;
66
67 /* was the ns entry fresh */
68 int fresh;
69};
70
71/* handle to a resolution process */
72struct GNUNET_GNS_ResolverHandle;
73
74/**
75 * processor for a resultion result
76 *
77 * @param cls the closure
78 * @param rh the resolution handle
79 * @param rd_count number of results
80 * @pram rd resukt data
81 */
82typedef void (*ResolutionResultProcessor) (void *cls,
83 struct GNUNET_GNS_ResolverHandle *rh,
84 uint32_t rd_count,
85 const struct GNUNET_NAMESTORE_RecordData *rd);
86
87/**
88 * Resoltion status indicator
89 * EXISTS: the name to lookup exists
90 * EXPIRED: the name in the record expired
91 */
92enum ResolutionStatus
93{
94 EXISTS = 1,
95 EXPIRED = 2
96};
97
98/**
99 * Handle to a currenty pending resolution
100 */
101struct GNUNET_GNS_ResolverHandle
102{
103 /* The name to resolve */
104 char *name;
105
106 /* has this query been answered? how many matches */
107 int answered;
108
109 /* the authoritative zone to query */
110 GNUNET_HashCode authority;
111
112 /* the name of the authoritative zone to query */
113 char *authority_name;
114
115 /**
116 * we have an authority in namestore that
117 * may be able to resolve
118 */
119 int authority_found;
120
121 /* a handle for dht lookups. should be NULL if no lookups are in progress */
122 struct GNUNET_DHT_GetHandle *get_handle;
123
124 /* timeout task for dht lookups */
125 GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
126
127 /* called when resolution phase finishes */
128 ResolutionResultProcessor proc;
129
130 /* closure passed to proc */
131 void* proc_cls;
132
133 /* DLL to store the authority chain */
134 struct AuthorityChain *authority_chain_head;
135
136 /* DLL to store the authority chain */
137 struct AuthorityChain *authority_chain_tail;
138
139 /* status of the resolution result */
140 enum ResolutionStatus status;
141
142};
143
144/**
145 * Handle to a record lookup
146 */
147struct RecordLookupHandle
148{
149 /* the record type to look up */
150 enum GNUNET_GNS_RecordType record_type;
151
152 /* the name to look up */
153 char *name;
154
155 /* Method to call on record resolution result */
156 ResolutionResultProcessor proc;
157
158 /* closure to pass to proc */
159 void* proc_cls;
160
161};
162
163/** 53/**
164 * Handle to a shorten operation from api 54 * Handle to a shorten operation from api
165 */ 55 */
@@ -216,28 +106,6 @@ struct ClientLookupHandle
216}; 106};
217 107
218/** 108/**
219 * Handle to a DNS intercepted
220 * reslution request
221 */
222struct InterceptLookupHandle
223{
224 /* the request handle to reply to */
225 struct GNUNET_DNS_RequestHandle *request_handle;
226
227 /* the dns parser packet received */
228 struct GNUNET_DNSPARSER_Packet *packet;
229
230 /* the query parsed from the packet */
231 struct GNUNET_DNSPARSER_Query *query;
232};
233
234
235/**
236 * Our handle to the DNS handler library
237 */
238struct GNUNET_DNS_Handle *dns_handle;
239
240/**
241 * Our handle to the DHT 109 * Our handle to the DHT
242 */ 110 */
243struct GNUNET_DHT_Handle *dht_handle; 111struct GNUNET_DHT_Handle *dht_handle;
@@ -274,11 +142,6 @@ static struct GNUNET_SERVER_NotificationContext *nc;
274GNUNET_HashCode zone_hash; 142GNUNET_HashCode zone_hash;
275 143
276/** 144/**
277 * Our tld. Maybe get from config file
278 */
279const char* gnunet_tld = ".gnunet";
280
281/**
282 * Useful for zone update for DHT put 145 * Useful for zone update for DHT put
283 */ 146 */
284static int num_public_records = 3600; 147static int num_public_records = 3600;
@@ -290,150 +153,6 @@ static struct GNUNET_TIME_Relative dht_update_interval;
290GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; 153GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
291 154
292/** 155/**
293 * Helper function to free resolver handle
294 *
295 * @rh the handle to free
296 */
297static void
298free_resolver_handle(struct GNUNET_GNS_ResolverHandle* rh)
299{
300 struct AuthorityChain *ac;
301 struct AuthorityChain *ac_next;
302
303 if (NULL == rh)
304 return;
305
306 GNUNET_free_non_null (rh->name);
307 GNUNET_free_non_null (rh->authority_name);
308
309 ac = rh->authority_chain_head;
310
311 while (NULL != ac)
312 {
313 ac_next = ac->next;
314 GNUNET_free_non_null (ac->name);
315 GNUNET_free(ac);
316 ac = ac_next;
317 }
318 GNUNET_free(rh);
319}
320
321
322/**
323 * Reply to dns request with the result from our lookup.
324 *
325 * @param cls the closure to the request (an InterceptLookupHandle)
326 * @param rh the request handle of the lookup
327 * @param rd_count the number of records to return
328 * @param rd the record data
329 */
330static void
331reply_to_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
332 const struct GNUNET_NAMESTORE_RecordData *rd)
333{
334 int i;
335 size_t len;
336 int ret;
337 char *buf;
338 struct InterceptLookupHandle* ilh = (struct InterceptLookupHandle*)cls;
339 struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
340 struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
341 struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
342 packet->answers = answer_records;
343 packet->additional_records = additional_records;
344
345 /**
346 * Put records in the DNS packet and modify it
347 * to a response
348 */
349 len = sizeof(struct GNUNET_DNSPARSER_Record*);
350 for (i=0; i < rd_count; i++)
351 {
352
353 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
354 "Adding type %d to DNS response\n", rd[i].record_type);
355 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
356 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", ilh->query->name);
357 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
358 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
359
360 if (rd[i].record_type == ilh->query->type)
361 {
362 answer_records[i].name = ilh->query->name;
363 answer_records[i].type = rd[i].record_type;
364 answer_records[i].data.raw.data_len = rd[i].data_size;
365 answer_records[i].data.raw.data = (char*)rd[i].data;
366 answer_records[i].expiration_time = rd[i].expiration;
367 answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
368 }
369 else
370 {
371 additional_records[i].name = ilh->query->name;
372 additional_records[i].type = rd[i].record_type;
373 additional_records[i].data.raw.data_len = rd[i].data_size;
374 additional_records[i].data.raw.data = (char*)rd[i].data;
375 additional_records[i].expiration_time = rd[i].expiration;
376 additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
377 }
378 }
379
380 packet->num_answers = rh->answered;
381 packet->num_additional_records = rd_count-(rh->answered);
382
383 if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
384 packet->flags.authoritative_answer = 1;
385 else
386 packet->flags.authoritative_answer = 0;
387
388 if (rd == NULL)
389 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
390 else
391 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
392
393 packet->flags.query_or_response = 1;
394
395
396 /**
397 * Reply to DNS
398 */
399 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
400 "Building DNS response\n");
401 ret = GNUNET_DNSPARSER_pack (packet,
402 1024, /* FIXME magic from dns redirector */
403 &buf,
404 &len);
405 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
406 "Built DNS response! (ret=%d,len=%d)\n", ret, len);
407 if (ret == GNUNET_OK)
408 {
409 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
410 "Answering DNS request\n");
411 GNUNET_DNS_request_answer(ilh->request_handle,
412 len,
413 buf);
414
415 GNUNET_free(buf);
416 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
417 }
418 else
419 {
420 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
421 "Error building DNS response! (ret=%d)", ret);
422 }
423
424 packet->num_answers = 0;
425 packet->answers = NULL;
426 packet->num_additional_records = 0;
427 packet->additional_records = NULL;
428 GNUNET_DNSPARSER_free_packet(packet);
429 //FIXME free more!
430 GNUNET_free((struct RecordLookupHandle*)rh->proc_cls);
431 free_resolver_handle(rh);
432 GNUNET_free(ilh);
433}
434
435
436/**
437 * Task run during shutdown. 156 * Task run during shutdown.
438 * 157 *
439 * @param cls unused 158 * @param cls unused
@@ -451,1115 +170,14 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
451 170
452 GNUNET_SERVER_notification_context_destroy (nc); 171 GNUNET_SERVER_notification_context_destroy (nc);
453 172
454 if (dns_handle) 173 gns_interceptor_stop();
455 GNUNET_DNS_disconnect(dns_handle); 174
456
457 GNUNET_NAMESTORE_disconnect(namestore_handle, 1); 175 GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
458 GNUNET_DHT_disconnect(dht_handle); 176 GNUNET_DHT_disconnect(dht_handle);
459} 177}
460 178
461 179
462/** 180/**
463 * Callback when record data is put into namestore
464 *
465 * @param cls the closure
466 * @param success GNUNET_OK on success
467 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
468 */
469void
470on_namestore_record_put_result(void *cls,
471 int32_t success,
472 const char *emsg)
473{
474 if (GNUNET_NO == success)
475 {
476 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
477 return;
478 }
479 else if (GNUNET_YES == success)
480 {
481 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
482 "records successfully put in namestore\n");
483 return;
484 }
485
486 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
487 "Error putting records into namestore: %s\n", emsg);
488}
489
490
491/**
492 * Handle timeout for DHT requests
493 *
494 * @param cls the request handle as closure
495 * @param tc the task context
496 */
497static void
498dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
499{
500 struct GNUNET_GNS_ResolverHandle *rh = cls;
501
502 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
503 "dht lookup for query %s timed out.\n",
504 rh->name);
505
506 GNUNET_DHT_get_stop (rh->get_handle);
507 rh->proc(rh->proc_cls, rh, 0, NULL);
508}
509
510
511/**
512 * Function called when we get a result from the dht
513 * for our record query
514 *
515 * @param cls the request handle
516 * @param exp lifetime
517 * @param key the key the record was stored under
518 * @param get_path get path
519 * @param get_path_length get path length
520 * @param put_path put path
521 * @param put_path_length put path length
522 * @param type the block type
523 * @param size the size of the record
524 * @param data the record data
525 */
526static void
527process_record_dht_result(void* cls,
528 struct GNUNET_TIME_Absolute exp,
529 const GNUNET_HashCode * key,
530 const struct GNUNET_PeerIdentity *get_path,
531 unsigned int get_path_length,
532 const struct GNUNET_PeerIdentity *put_path,
533 unsigned int put_path_length,
534 enum GNUNET_BLOCK_Type type,
535 size_t size, const void *data)
536{
537 struct GNUNET_GNS_ResolverHandle *rh;
538 struct RecordLookupHandle *rlh;
539 struct GNSNameRecordBlock *nrb;
540 uint32_t num_records;
541 char* name = NULL;
542 char* rd_data = (char*)data;
543 int i;
544 int rd_size;
545
546 GNUNET_HashCode zone, name_hash;
547 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
548
549 if (data == NULL)
550 return;
551
552 //FIXME maybe check expiration here, check block type
553
554 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
555 rlh = (struct RecordLookupHandle *) rh->proc_cls;
556 nrb = (struct GNSNameRecordBlock*)data;
557
558 /* stop lookup and timeout task */
559 GNUNET_DHT_get_stop (rh->get_handle);
560 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
561
562 rh->get_handle = NULL;
563 name = (char*)&nrb[1];
564 num_records = ntohl(nrb->rd_count);
565 {
566 struct GNUNET_NAMESTORE_RecordData rd[num_records];
567
568 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
569 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
570
571 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
572 rd_data,
573 num_records,
574 rd))
575 {
576 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
577 return;
578 }
579
580 for (i=0; i<num_records; i++)
581 {
582 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
583 "Got name: %s (wanted %s)\n", name, rh->name);
584 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
585 "Got type: %d\n",
586 rd[i].record_type);
587 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
588 "Got data length: %d\n", rd[i].data_size);
589 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
590 "Got flag %d\n", rd[i].flags);
591
592 if ((strcmp(name, rh->name) == 0) &&
593 (rd[i].record_type == rlh->record_type))
594 {
595 rh->answered++;
596 }
597
598 }
599
600 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
601 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
602
603 /**
604 * FIXME check pubkey against existing key in namestore?
605 * https://gnunet.org/bugs/view.php?id=2179
606 */
607
608 /* Save to namestore */
609 GNUNET_NAMESTORE_record_put (namestore_handle,
610 &nrb->public_key,
611 name,
612 exp,
613 num_records,
614 rd,
615 &nrb->signature,
616 &on_namestore_record_put_result, //cont
617 NULL); //cls
618
619 if (rh->answered)
620 rh->proc(rh->proc_cls, rh, num_records, rd);
621 else
622 rh->proc(rh->proc_cls, rh, 0, NULL);
623 }
624
625}
626
627
628/**
629 * Start DHT lookup for a (name -> query->record_type) record in
630 * rh->authority's zone
631 *
632 * @param rh the pending gns query context
633 */
634static void
635resolve_record_dht(struct GNUNET_GNS_ResolverHandle *rh)
636{
637 uint32_t xquery;
638 GNUNET_HashCode name_hash;
639 GNUNET_HashCode lookup_key;
640 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
641 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
642
643 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
644 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
645 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
646
647 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
648 "starting dht lookup for %s with key: %s\n",
649 rh->name, (char*)&lookup_key_string);
650
651 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
652 &dht_lookup_timeout, rh);
653
654 xquery = htonl(rlh->record_type);
655 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
656 DHT_OPERATION_TIMEOUT,
657 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
658 &lookup_key,
659 DHT_GNS_REPLICATION_LEVEL,
660 GNUNET_DHT_RO_NONE,
661 &xquery,
662 sizeof(xquery),
663 &process_record_dht_result,
664 rh);
665
666}
667
668
669/**
670 * Namestore calls this function if we have record for this name.
671 * (or with rd_count=0 to indicate no matches)
672 *
673 * @param cls the pending query
674 * @param key the key of the zone we did the lookup
675 * @param expiration expiration date of the namestore entry
676 * @param name the name for which we need an authority
677 * @param rd_count the number of records with 'name'
678 * @param rd the record data
679 * @param signature the signature of the authority for the record data
680 */
681static void
682process_record_lookup_ns(void* cls,
683 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
684 struct GNUNET_TIME_Absolute expiration,
685 const char *name, unsigned int rd_count,
686 const struct GNUNET_NAMESTORE_RecordData *rd,
687 const struct GNUNET_CRYPTO_RsaSignature *signature)
688{
689 struct GNUNET_GNS_ResolverHandle *rh;
690 struct RecordLookupHandle *rlh;
691 struct GNUNET_TIME_Relative remaining_time;
692 GNUNET_HashCode zone;
693
694 rh = (struct GNUNET_GNS_ResolverHandle *) cls;
695 rlh = (struct RecordLookupHandle *)rh->proc_cls;
696 GNUNET_CRYPTO_hash(key,
697 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
698 &zone);
699 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
700
701 rh->status = 0;
702
703 if (name != NULL)
704 {
705 rh->status |= EXISTS;
706 }
707
708 if (remaining_time.rel_value == 0)
709 {
710 rh->status |= EXPIRED;
711 }
712
713 if (rd_count == 0)
714 {
715 /**
716 * Lookup terminated and no results
717 */
718 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
719 "Namestore lookup for %s terminated without results\n", name);
720
721 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
722 "Record %s unknown in namestore\n",
723 rh->name);
724 /**
725 * Our zone and no result? Cannot resolve TT
726 */
727 rh->proc(rh->proc_cls, rh, 0, NULL);
728 return;
729
730 }
731 else
732 {
733
734 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
735 "Processing additional result %s from namestore\n", name);
736 int i;
737 for (i=0; i<rd_count;i++)
738 {
739
740 if (rd[i].record_type != rlh->record_type)
741 continue;
742
743 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
744 == 0)
745 {
746 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
747 continue;
748 }
749
750 rh->answered++;
751
752 }
753
754 /**
755 * no answers found
756 */
757 if (rh->answered == 0)
758 {
759 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
760 "No answers found. This is odd!\n");
761 rh->proc(rh->proc_cls, rh, 0, NULL);
762 return;
763 }
764
765 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
766 rh->answered);
767
768 rh->proc(rh->proc_cls, rh, rd_count, rd);
769 }
770}
771
772
773/**
774 * The final phase of resolution.
775 * rh->name is a name that is canonical and we do not have a delegation.
776 * Query namestore for this record
777 *
778 * @param rh the pending lookup
779 */
780static void
781resolve_record_ns(struct GNUNET_GNS_ResolverHandle *rh)
782{
783 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
784
785 /**
786 * Try to resolve this record in our namestore.
787 * The name to resolve is now in rh->authority_name
788 * since we tried to resolve it to an authority
789 * and failed.
790 **/
791 GNUNET_NAMESTORE_lookup_record(namestore_handle,
792 &rh->authority,
793 rh->name,
794 rlh->record_type,
795 &process_record_lookup_ns,
796 rh);
797}
798
799
800/**
801 * Handle timeout for DHT requests
802 *
803 * @param cls the request handle as closure
804 * @param tc the task context
805 */
806static void
807dht_authority_lookup_timeout(void *cls,
808 const struct GNUNET_SCHEDULER_TaskContext *tc)
809{
810 struct GNUNET_GNS_ResolverHandle *rh = cls;
811
812 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
813 "dht lookup for query %s timed out.\n",
814 rh->name);
815
816 GNUNET_DHT_get_stop (rh->get_handle);
817 if (strcmp(rh->name, "") == 0)
818 {
819 /*
820 * promote authority back to name and try to resolve record
821 */
822 strcpy(rh->name, rh->authority_name);
823 }
824 rh->proc(rh->proc_cls, rh, 0, NULL);
825}
826
827/* Prototype */
828static void resolve_delegation_dht(struct GNUNET_GNS_ResolverHandle *rh);
829
830/**
831 * Function called when we get a result from the dht
832 * for our query. Recursively tries to resolve authorities
833 * for name in DHT.
834 *
835 * @param cls the request handle
836 * @param exp lifetime
837 * @param key the key the record was stored under
838 * @param get_path get path
839 * @param get_path_length get path length
840 * @param put_path put path
841 * @param put_path_length put path length
842 * @param type the block type
843 * @param size the size of the record
844 * @param data the record data
845 */
846static void
847process_delegation_result_dht(void* cls,
848 struct GNUNET_TIME_Absolute exp,
849 const GNUNET_HashCode * key,
850 const struct GNUNET_PeerIdentity *get_path,
851 unsigned int get_path_length,
852 const struct GNUNET_PeerIdentity *put_path,
853 unsigned int put_path_length,
854 enum GNUNET_BLOCK_Type type,
855 size_t size, const void *data)
856{
857 struct GNUNET_GNS_ResolverHandle *rh;
858 struct GNSNameRecordBlock *nrb;
859 uint32_t num_records;
860 char* name = NULL;
861 char* rd_data = (char*) data;
862 int i;
863 int rd_size;
864 GNUNET_HashCode zone, name_hash;
865
866 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
867
868 if (data == NULL)
869 return;
870
871 //FIXME check expiration?
872
873 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
874 nrb = (struct GNSNameRecordBlock*)data;
875
876 /* stop dht lookup and timeout task */
877 GNUNET_DHT_get_stop (rh->get_handle);
878 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
879
880 rh->get_handle = NULL;
881 num_records = ntohl(nrb->rd_count);
882 name = (char*)&nrb[1];
883 {
884 struct GNUNET_NAMESTORE_RecordData rd[num_records];
885
886 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
887 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
888
889 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
890 rd_data,
891 num_records,
892 rd))
893 {
894 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
895 return;
896 }
897
898 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
899 "Got name: %s (wanted %s)\n", name, rh->authority_name);
900 for (i=0; i<num_records; i++)
901 {
902
903 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
904 "Got name: %s (wanted %s)\n", name, rh->authority_name);
905 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
906 "Got type: %d (wanted %d)\n",
907 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
908 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
909 "Got data length: %d\n", rd[i].data_size);
910 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
911 "Got flag %d\n", rd[i].flags);
912
913 if ((strcmp(name, rh->authority_name) == 0) &&
914 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
915 {
916 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
917 rh->answered = 1;
918 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
919 struct AuthorityChain *auth =
920 GNUNET_malloc(sizeof(struct AuthorityChain));
921 auth->zone = rh->authority;
922 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
923 memset(auth->name, 0, strlen(rh->authority_name)+1);
924 strcpy(auth->name, rh->authority_name);
925 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
926 rh->authority_chain_tail,
927 auth);
928 }
929
930 }
931
932
933 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
934 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
935
936 /* Save to namestore */
937 if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
938 {
939 GNUNET_NAMESTORE_record_put (namestore_handle,
940 &nrb->public_key,
941 name,
942 exp,
943 num_records,
944 rd,
945 &nrb->signature,
946 &on_namestore_record_put_result, //cont
947 NULL); //cls
948 }
949 }
950
951 if (rh->answered)
952 {
953 rh->answered = 0;
954 /**
955 * delegate
956 * FIXME in this case. should we ask namestore again?
957 */
958 if (strcmp(rh->name, "") == 0)
959 rh->proc(rh->proc_cls, rh, 0, NULL);
960 else
961 resolve_delegation_dht(rh);
962 return;
963 }
964
965 /**
966 * should never get here unless false dht key/put
967 * block plugin should handle this
968 **/
969 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup error!\n");
970 GNUNET_break(0);
971}
972
973
974/**
975 * Process DHT lookup result for record.
976 *
977 * @param cls the closure
978 * @param rh resolver handle
979 * @param rd_count number of results (always 0)
980 * @param rd record data (always NULL)
981 */
982static void
983process_record_result_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
984 unsigned int rd_count,
985 const struct GNUNET_NAMESTORE_RecordData *rd)
986{
987 struct RecordLookupHandle* rlh;
988 rlh = (struct RecordLookupHandle*)cls;
989 if (rd_count == 0)
990 {
991 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
992 "No records for %s found in DHT. Aborting\n",
993 rh->name);
994 /* give up, cannot resolve */
995 rlh->proc(rlh->proc_cls, rh, 0, NULL);
996 return;
997 }
998
999 /* results found yay */
1000 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1001 "Record resolved from namestore!");
1002 rlh->proc(rlh->proc_cls, rh, rd_count, rd);
1003
1004}
1005
1006
1007/**
1008 * Process namestore lookup result for record.
1009 *
1010 * @param cls the closure
1011 * @param rh resolver handle
1012 * @param rd_count number of results (always 0)
1013 * @param rd record data (always NULL)
1014 */
1015static void
1016process_record_result_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1017 unsigned int rd_count,
1018 const struct GNUNET_NAMESTORE_RecordData *rd)
1019{
1020 struct RecordLookupHandle* rlh;
1021 rlh = (struct RecordLookupHandle*) cls;
1022 if (rd_count == 0)
1023 {
1024 /* ns entry expired. try dht */
1025 if (rh->status & (EXPIRED | !EXISTS))
1026 {
1027 rh->proc = &process_record_result_dht;
1028 resolve_record_dht(rh);
1029 return;
1030 }
1031 /* give up, cannot resolve */
1032 rlh->proc(rlh->proc_cls, rh, 0, NULL);
1033 return;
1034 }
1035
1036 /* results found yay */
1037 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1038 "Record resolved from namestore!");
1039 rlh->proc(rlh->proc_cls, rh, rd_count, rd);
1040
1041}
1042
1043
1044/**
1045 * Determine if this name is canonical.
1046 * i.e.
1047 * a.b.gnunet = not canonical
1048 * a = canonical
1049 *
1050 * @param name the name to test
1051 * @return 1 if canonical
1052 */
1053static int
1054is_canonical(char* name)
1055{
1056 uint32_t len = strlen(name);
1057 int i;
1058
1059 for (i=0; i<len; i++)
1060 {
1061 if (*(name+i) == '.')
1062 return 0;
1063 }
1064 return 1;
1065}
1066
1067/**
1068 * Move one level up in the domain hierarchy and return the
1069 * passed top level domain.
1070 *
1071 * @param name the domain
1072 * @param dest the destination where the tld will be put
1073 */
1074void
1075pop_tld(char* name, char* dest)
1076{
1077 uint32_t len;
1078
1079 if (is_canonical(name))
1080 {
1081 strcpy(dest, name);
1082 strcpy(name, "");
1083 return;
1084 }
1085
1086 for (len = strlen(name); len > 0; len--)
1087 {
1088 if (*(name+len) == '.')
1089 break;
1090 }
1091
1092 //Was canonical?
1093 if (len == 0)
1094 return;
1095
1096 name[len] = '\0';
1097
1098 strcpy(dest, (name+len+1));
1099}
1100
1101/**
1102 * DHT resolution for delegation finished. Processing result.
1103 *
1104 * @param cls the closure
1105 * @param rh resolver handle
1106 * @param rd_count number of results (always 0)
1107 * @param rd record data (always NULL)
1108 */
1109static void
1110process_delegation_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1111 unsigned int rd_count,
1112 const struct GNUNET_NAMESTORE_RecordData *rd)
1113{
1114 struct RecordLookupHandle* rlh;
1115 rlh = (struct RecordLookupHandle*) cls;
1116
1117 if (strcmp(rh->name, "") == 0)
1118 {
1119 /* We resolved full name for delegation. resolving record */
1120 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1121 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1122 rh->proc = &process_record_result_ns;
1123 resolve_record_ns(rh);
1124 return;
1125 }
1126
1127 /**
1128 * we still have some left
1129 **/
1130 if (is_canonical(rh->name))
1131 {
1132 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1133 "Resolving canonical record %s in ns\n", rh->name);
1134 rh->proc = &process_record_result_ns;
1135 resolve_record_ns(rh);
1136 return;
1137 }
1138 /* give up, cannot resolve */
1139 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1140 "Cannot fully resolve delegation for %s via DHT!\n",
1141 rh->name);
1142 rlh->proc(rlh->proc_cls, rh, 0, NULL);
1143}
1144
1145
1146/**
1147 * Start DHT lookup for a name -> PKEY (compare NS) record in
1148 * rh->authority's zone
1149 *
1150 * @param rh the pending gns query
1151 * @param name the name of the PKEY record
1152 */
1153static void
1154resolve_delegation_dht(struct GNUNET_GNS_ResolverHandle *rh)
1155{
1156 uint32_t xquery;
1157 GNUNET_HashCode name_hash;
1158 GNUNET_HashCode lookup_key;
1159
1160 GNUNET_CRYPTO_hash(rh->authority_name,
1161 strlen(rh->authority_name),
1162 &name_hash);
1163 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1164
1165 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1166 &dht_authority_lookup_timeout,
1167 rh);
1168
1169 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1170
1171 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1172 DHT_OPERATION_TIMEOUT,
1173 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1174 &lookup_key,
1175 DHT_GNS_REPLICATION_LEVEL,
1176 GNUNET_DHT_RO_NONE,
1177 &xquery,
1178 sizeof(xquery),
1179 &process_delegation_result_dht,
1180 rh);
1181
1182}
1183
1184
1185/**
1186 * Namestore resolution for delegation finished. Processing result.
1187 *
1188 * @param cls the closure
1189 * @param rh resolver handle
1190 * @param rd_count number of results (always 0)
1191 * @param rd record data (always NULL)
1192 */
1193static void
1194process_delegation_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1195 unsigned int rd_count,
1196 const struct GNUNET_NAMESTORE_RecordData *rd)
1197{
1198 struct RecordLookupHandle* rlh;
1199 rlh = (struct RecordLookupHandle*) cls;
1200
1201 if (strcmp(rh->name, "") == 0)
1202 {
1203 /* We resolved full name for delegation. resolving record */
1204 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1205 "Resolved full name for delegation. resolving record ''\n");
1206 rh->proc = &process_record_result_ns;
1207 resolve_record_ns(rh);
1208 return;
1209 }
1210
1211 /**
1212 * we still have some left
1213 * check if ns entry is fresh
1214 **/
1215 if (rh->status & (EXISTS | !EXPIRED))
1216 {
1217 if (is_canonical(rh->name))
1218 {
1219 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1220 "Resolving canonical record %s\n", rh->name);
1221 rh->proc = &process_record_result_ns;
1222 resolve_record_ns(rh);
1223 }
1224 else
1225 {
1226 /* give up, cannot resolve */
1227 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1228 "Cannot fully resolve delegation for %s!\n",
1229 rh->name);
1230 rlh->proc(rlh->proc_cls, rh, 0, NULL);
1231 }
1232 return;
1233 }
1234
1235 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1236 "Trying to resolve delegation for %s via DHT\n",
1237 rh->name);
1238 rh->proc = &process_delegation_dht;
1239 resolve_delegation_dht(rh);
1240}
1241
1242//Prototype
1243static void resolve_delegation_ns(struct GNUNET_GNS_ResolverHandle *rh);
1244
1245/**
1246 * This is a callback function that should give us only PKEY
1247 * records. Used to query the namestore for the authority (PKEY)
1248 * for 'name'. It will recursively try to resolve the
1249 * authority for a given name from the namestore.
1250 *
1251 * @param cls the pending query
1252 * @param key the key of the zone we did the lookup
1253 * @param expiration expiration date of the record data set in the namestore
1254 * @param name the name for which we need an authority
1255 * @param rd_count the number of records with 'name'
1256 * @param rd the record data
1257 * @param signature the signature of the authority for the record data
1258 */
1259static void
1260process_delegation_result_ns(void* cls,
1261 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1262 struct GNUNET_TIME_Absolute expiration,
1263 const char *name,
1264 unsigned int rd_count,
1265 const struct GNUNET_NAMESTORE_RecordData *rd,
1266 const struct GNUNET_CRYPTO_RsaSignature *signature)
1267{
1268 struct GNUNET_GNS_ResolverHandle *rh;
1269 struct GNUNET_TIME_Relative remaining_time;
1270 GNUNET_HashCode zone;
1271 char* new_name;
1272
1273 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1274 rd_count);
1275
1276 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1277 GNUNET_CRYPTO_hash(key,
1278 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1279 &zone);
1280 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1281
1282 rh->status = 0;
1283
1284 if (name != NULL)
1285 {
1286 rh->status |= EXISTS;
1287 }
1288
1289 if (remaining_time.rel_value == 0)
1290 {
1291 rh->status |= EXPIRED;
1292 }
1293
1294 /**
1295 * No authority found in namestore.
1296 */
1297 if (rd_count == 0)
1298 {
1299 /**
1300 * We did not find an authority in the namestore
1301 */
1302
1303 /**
1304 * No PKEY in zone.
1305 * Promote this authority back to a name maybe it is
1306 * our record.
1307 */
1308 if (strcmp(rh->name, "") == 0)
1309 {
1310 /* simply promote back */
1311 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1312 "Promoting %s back to name\n", rh->authority_name);
1313 strcpy(rh->name, rh->authority_name);
1314 }
1315 else
1316 {
1317 /* add back to existing name */
1318 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1319 "Adding %s back to %s\n",
1320 rh->authority_name, rh->name);
1321 new_name = GNUNET_malloc(strlen(rh->name)
1322 + strlen(rh->authority_name) + 2);
1323 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1324 strcpy(new_name, rh->name);
1325 strcpy(new_name+strlen(new_name)+1, ".");
1326 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1327 GNUNET_free(rh->name);
1328 rh->name = new_name;
1329 }
1330 rh->proc(rh->proc_cls, rh, 0, NULL);
1331 return;
1332 }
1333
1334 //Note only 1 pkey should have been returned.. anything else would be strange
1335 /**
1336 * We found an authority that may be able to help us
1337 * move on with query
1338 */
1339 int i;
1340 for (i=0; i<rd_count;i++)
1341 {
1342
1343 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1344 continue;
1345
1346 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1347 == 0)
1348 {
1349 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1350 if (remaining_time.rel_value == 0)
1351 {
1352 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1353 "This dht entry is expired.\n");
1354 rh->authority_chain_head->fresh = 0;
1355 rh->proc(rh->proc_cls, rh, 0, NULL);
1356 return;
1357 }
1358
1359 continue;
1360 }
1361
1362 /**
1363 * Resolve rest of query with new authority
1364 */
1365 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1366 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1367 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1368 auth->zone = rh->authority;
1369 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1370 memset(auth->name, 0, strlen(rh->authority_name)+1);
1371 strcpy(auth->name, rh->authority_name);
1372 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1373 rh->authority_chain_tail,
1374 auth);
1375
1376 /**
1377 * We are done with PKEY resolution if name is empty
1378 * else resolve again with new authority
1379 */
1380 if (strcmp(rh->name, "") == 0)
1381 rh->proc(rh->proc_cls, rh, 0, NULL);
1382 else
1383 resolve_delegation_ns(rh);
1384 return;
1385 }
1386
1387 /**
1388 * no answers found
1389 */
1390 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1391 "Authority lookup successful but no PKEY... never get here\n");
1392 rh->proc(rh->proc_cls, rh, 0, NULL);
1393}
1394
1395
1396/**
1397 * Resolve the delegation chain for the request in our namestore
1398 *
1399 * @param rh the resolver handle
1400 */
1401static void
1402resolve_delegation_ns(struct GNUNET_GNS_ResolverHandle *rh)
1403{
1404
1405 pop_tld(rh->name, rh->authority_name);
1406 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1407 &rh->authority,
1408 rh->authority_name,
1409 GNUNET_GNS_RECORD_PKEY,
1410 &process_delegation_result_ns,
1411 rh);
1412
1413}
1414
1415/**
1416 * Entry point for name resolution
1417 * Setup a new query and try to resolve
1418 *
1419 * @param request the request handle of the DNS request from a client
1420 * @param p the DNS query packet we received
1421 * @param q the DNS query we received parsed from p
1422 */
1423static void
1424start_resolution_for_dns(struct GNUNET_DNS_RequestHandle *request,
1425 struct GNUNET_DNSPARSER_Packet *p,
1426 struct GNUNET_DNSPARSER_Query *q)
1427{
1428 struct GNUNET_GNS_ResolverHandle *rh;
1429 struct RecordLookupHandle* rlh;
1430 struct InterceptLookupHandle* ilh;
1431
1432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433 "Starting resolution for %s (type=%d)!\n",
1434 q->name, q->type);
1435
1436 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1437 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1438 ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle));
1439 ilh->packet = p;
1440 ilh->query = q;
1441 ilh->request_handle = request;
1442
1443 rh->authority = zone_hash;
1444
1445 rlh->record_type = q->type;
1446 rlh->name = q->name;
1447 rlh->proc = &reply_to_dns;
1448 rlh->proc_cls = ilh;
1449
1450 rh->proc_cls = rlh;
1451
1452 rh->name = GNUNET_malloc(strlen(q->name)
1453 - strlen(gnunet_tld) + 1);
1454 memset(rh->name, 0,
1455 strlen(q->name)-strlen(gnunet_tld) + 1);
1456 memcpy(rh->name, q->name,
1457 strlen(q->name)-strlen(gnunet_tld));
1458
1459 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1460
1461 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1462 rh->authority_chain_head->prev = NULL;
1463 rh->authority_chain_head->next = NULL;
1464 rh->authority_chain_tail = rh->authority_chain_head;
1465 rh->authority_chain_head->zone = zone_hash;
1466
1467 /* Start resolution in our zone */
1468 rh->proc = &process_delegation_ns;
1469 resolve_delegation_ns(rh);
1470}
1471
1472
1473
1474/**
1475 * The DNS request handler
1476 * Called for every incoming DNS request.
1477 *
1478 * @param cls closure
1479 * @param rh request handle to user for reply
1480 * @param request_length number of bytes in request
1481 * @param request udp payload of the DNS request
1482 */
1483static void
1484handle_dns_request(void *cls,
1485 struct GNUNET_DNS_RequestHandle *rh,
1486 size_t request_length,
1487 const char *request)
1488{
1489 struct GNUNET_DNSPARSER_Packet *p;
1490 int i;
1491 char *tldoffset;
1492
1493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1494 p = GNUNET_DNSPARSER_parse (request, request_length);
1495
1496 if (NULL == p)
1497 {
1498 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1499 "Received malformed DNS packet, leaving it untouched\n");
1500 GNUNET_DNS_request_forward (rh);
1501 GNUNET_DNSPARSER_free_packet (p);
1502 return;
1503 }
1504
1505 /**
1506 * Check tld and decide if we or
1507 * legacy dns is responsible
1508 *
1509 * FIXME now in theory there could be more than 1 query in the request
1510 * but if this is case we get into trouble:
1511 * either we query the GNS or the DNS. We cannot do both!
1512 * So I suggest to either only allow a single query per request or
1513 * only allow GNS or DNS requests.
1514 * The way it is implemented here now is buggy and will lead to erratic
1515 * behaviour (if multiple queries are present).
1516 */
1517 if (p->num_queries == 0)
1518 {
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 "No Queries in DNS packet... forwarding\n");
1521 GNUNET_DNS_request_forward (rh);
1522 GNUNET_DNSPARSER_free_packet(p);
1523 return;
1524 }
1525
1526 if (p->num_queries > 1)
1527 {
1528 /* Note: We could also look for .gnunet */
1529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530 ">1 queriy in DNS packet... odd. We only process #1\n");
1531 }
1532
1533
1534 /**
1535 * Check for .gnunet
1536 */
1537 tldoffset = p->queries[0].name + strlen(p->queries[0].name) - 1;
1538
1539 for (i=0; i<strlen(p->queries[0].name); i++)
1540 {
1541 if (*(tldoffset-i) == '.')
1542 break;
1543 }
1544
1545 if ((i==strlen(gnunet_tld)-1) && (0 == strcmp(tldoffset-i, gnunet_tld)))
1546 {
1547 start_resolution_for_dns(rh, p, p->queries);
1548 }
1549 else
1550 {
1551 /**
1552 * This request does not concern us. Forward to real DNS.
1553 */
1554 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1555 "Request for %s is forwarded to DNS\n", p->queries[0].name);
1556 GNUNET_DNS_request_forward (rh);
1557 GNUNET_DNSPARSER_free_packet (p);
1558 }
1559
1560}
1561
1562/**
1563 * Method called periodicattluy that triggers 181 * Method called periodicattluy that triggers
1564 * iteration over root zone 182 * iteration over root zone
1565 * 183 *
@@ -1727,577 +345,8 @@ update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1727 NULL); 345 NULL);
1728} 346}
1729 347
1730//Prototype
1731static void send_shorten_response(const char* name,
1732 struct ClientShortenHandle *csh);
1733static void
1734process_shorten_pseu_lookup_ns(void *cls,
1735 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1736 struct GNUNET_TIME_Absolute expire,
1737 const char *name,
1738 unsigned int rd_len,
1739 const struct GNUNET_NAMESTORE_RecordData *rd,
1740 const struct GNUNET_CRYPTO_RsaSignature *signature)
1741{
1742 struct GNUNET_GNS_ResolverHandle *rh =
1743 (struct GNUNET_GNS_ResolverHandle *)cls;
1744 struct GNUNET_TIME_Relative remaining_time;
1745
1746 GNUNET_TIME_absolute_get_remaining (expire);
1747 rh->status = 0;
1748
1749 if (name != NULL)
1750 {
1751 rh->status |= EXISTS;
1752 }
1753
1754 if (remaining_time.rel_value == 0)
1755 {
1756 rh->status |= EXPIRED;
1757 }
1758
1759 rh->proc(rh->proc_cls, rh, rd_len, rd);
1760}
1761
1762
1763/**
1764 * Function called when we get a result from the dht
1765 * for our record query
1766 *
1767 * @param cls the request handle
1768 * @param exp lifetime
1769 * @param key the key the record was stored under
1770 * @param get_path get path
1771 * @param get_path_length get path length
1772 * @param put_path put path
1773 * @param put_path_length put path length
1774 * @param type the block type
1775 * @param size the size of the record
1776 * @param data the record data
1777 */
1778static void
1779process_pseu_dht_result(void* cls,
1780 struct GNUNET_TIME_Absolute exp,
1781 const GNUNET_HashCode * key,
1782 const struct GNUNET_PeerIdentity *get_path,
1783 unsigned int get_path_length,
1784 const struct GNUNET_PeerIdentity *put_path,
1785 unsigned int put_path_length,
1786 enum GNUNET_BLOCK_Type type,
1787 size_t size, const void *data)
1788{
1789 struct GNUNET_GNS_ResolverHandle *rh;
1790 struct RecordLookupHandle *rlh;
1791 struct GNSNameRecordBlock *nrb;
1792 uint32_t num_records;
1793 char* name = NULL;
1794 char* rd_data = (char*)data;
1795 int i;
1796 int rd_size;
1797
1798 GNUNET_HashCode zone, name_hash;
1799 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got PSEU dht result (size=%d)\n", size);
1800
1801 if (data == NULL)
1802 return;
1803
1804 //FIXME maybe check expiration here, check block type
1805
1806 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1807 rlh = (struct RecordLookupHandle *) rh->proc_cls;
1808 nrb = (struct GNSNameRecordBlock*)data;
1809
1810 /* stop lookup and timeout task */
1811 GNUNET_DHT_get_stop (rh->get_handle);
1812 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
1813
1814 rh->get_handle = NULL;
1815 name = (char*)&nrb[1];
1816 num_records = ntohl(nrb->rd_count);
1817 {
1818 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1819
1820 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1821 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1822
1823 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1824 rd_data,
1825 num_records,
1826 rd))
1827 {
1828 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
1829 return;
1830 }
1831
1832 for (i=0; i<num_records; i++)
1833 {
1834 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1835 "Got name: %s (wanted %s)\n", name, rh->name);
1836 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1837 "Got type: %d\n",
1838 rd[i].record_type);
1839 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1840 "Got data length: %d\n", rd[i].data_size);
1841 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1842 "Got flag %d\n", rd[i].flags);
1843
1844 if ((strcmp(name, "+") == 0) &&
1845 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
1846 {
1847 rh->answered++;
1848 }
1849
1850 }
1851
1852 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1853 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
1854
1855 /**
1856 * FIXME check pubkey against existing key in namestore?
1857 * https://gnunet.org/bugs/view.php?id=2179
1858 */
1859
1860 /* Save to namestore */
1861 GNUNET_NAMESTORE_record_put (namestore_handle,
1862 &nrb->public_key,
1863 name,
1864 exp,
1865 num_records,
1866 rd,
1867 &nrb->signature,
1868 &on_namestore_record_put_result, //cont
1869 NULL); //cls
1870
1871 if (rh->answered)
1872 rh->proc(rh->proc_cls, rh, num_records, rd);
1873 else
1874 rh->proc(rh->proc_cls, rh, 0, NULL);
1875 }
1876
1877}
1878 348
1879 349/* END DHT ZONE PROPAGATION */
1880/**
1881 * Start DHT lookup for a PSEUdonym record in
1882 * rh->authority's zone
1883 *
1884 * @param rh the pending gns query
1885 */
1886static void
1887resolve_pseu_dht(struct GNUNET_GNS_ResolverHandle *rh)
1888{
1889 uint32_t xquery;
1890 GNUNET_HashCode name_hash;
1891 GNUNET_HashCode lookup_key;
1892
1893 GNUNET_CRYPTO_hash("+",
1894 strlen("+"),
1895 &name_hash);
1896
1897 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1898
1899 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1900 &dht_lookup_timeout,
1901 rh);
1902
1903 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
1904
1905 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1906 DHT_OPERATION_TIMEOUT,
1907 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1908 &lookup_key,
1909 DHT_GNS_REPLICATION_LEVEL,
1910 GNUNET_DHT_RO_NONE,
1911 &xquery,
1912 sizeof(xquery),
1913 &process_pseu_dht_result,
1914 rh);
1915
1916}
1917
1918//Prototype
1919static void
1920handle_shorten_pseu_ns_result(void* cls,
1921 struct GNUNET_GNS_ResolverHandle *rh,
1922 uint32_t rd_count,
1923 const struct GNUNET_NAMESTORE_RecordData *rd);
1924
1925static void
1926handle_shorten_zone_to_name(void *cls,
1927 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1928 struct GNUNET_TIME_Absolute expire,
1929 const char *name,
1930 unsigned int rd_len,
1931 const struct GNUNET_NAMESTORE_RecordData *rd,
1932 const struct GNUNET_CRYPTO_RsaSignature *signature)
1933{
1934 struct GNUNET_GNS_ResolverHandle *rh =
1935 (struct GNUNET_GNS_ResolverHandle *)cls;
1936 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) rh->proc_cls;
1937
1938 char* result;
1939 size_t answer_len;
1940
1941 /* we found a match in our own zone */
1942 if (rd_len != 0)
1943 {
1944 answer_len = strlen(rh->name) + strlen(name) + strlen(gnunet_tld) + 2;
1945 result = GNUNET_malloc(answer_len);
1946 memset(result, 0, answer_len);
1947 strcpy(result, rh->name);
1948 strcpy(result+strlen(rh->name), ".");
1949 strcpy(result+strlen(rh->name)+1, name);
1950 strcpy(result+strlen(rh->name)+strlen(name), gnunet_tld);
1951
1952 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1953 "Sending shorten result %s\n", result);
1954
1955 send_shorten_response(result, csh);
1956 free_resolver_handle(rh);
1957 GNUNET_free(result);
1958 }
1959 else
1960 {
1961 /**
1962 * Nothing in our zone
1963 * check PSEU for this authority in namestore
1964 */
1965 rh->proc = &handle_shorten_pseu_ns_result;
1966 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1967 &rh->authority_chain_head->zone,
1968 "+",
1969 GNUNET_GNS_RECORD_PSEU,
1970 &process_shorten_pseu_lookup_ns,
1971 rh);
1972 }
1973}
1974
1975/**
1976 * Process result from namestore delegation lookup
1977 * for shorten operation
1978 *
1979 * @param cls the client shorten handle
1980 * @param rh the resolver handle
1981 * @param rd_count number of results (0)
1982 * @param rd data (NULL)
1983 */
1984void
1985handle_shorten_pseu_dht_result(void* cls,
1986 struct GNUNET_GNS_ResolverHandle *rh,
1987 uint32_t rd_len,
1988 const struct GNUNET_NAMESTORE_RecordData *rd)
1989{
1990 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1991 struct AuthorityChain *auth_chain;
1992 char* pseu;
1993 char* result;
1994 char* new_name;
1995 size_t answer_len;
1996 int i;
1997
1998 /**
1999 * PSEU found
2000 */
2001 if (rd_len != 0)
2002 {
2003 for (i=0; i < rd_len; i++)
2004 {
2005 if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
2006 {
2007 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2008 "Found PSEU %s\n", (char*) rd[i].data);
2009 break;
2010 }
2011 }
2012
2013 pseu = (char*) rd[i].data;
2014 answer_len = strlen(rh->name) + strlen(pseu) + strlen(gnunet_tld) + 2;
2015 result = GNUNET_malloc(answer_len);
2016 memset(result, 0, answer_len);
2017 strcpy(result, rh->name);
2018 strcpy(result+strlen(rh->name), ".");
2019 strcpy(result+strlen(rh->name)+1, pseu);
2020 strcpy(result+strlen(rh->name)+strlen(pseu)+1, gnunet_tld);
2021
2022 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2023 "Sending pseudonym shorten result %s\n", result);
2024
2025 send_shorten_response(result, csh);
2026 free_resolver_handle(rh);
2027 GNUNET_free(result);
2028 return;
2029 }
2030
2031 /**
2032 * No PSEU found.
2033 * continue with next authority
2034 * backtrack
2035 */
2036 auth_chain = rh->authority_chain_head;
2037
2038 if ((auth_chain->next->next == NULL) &&
2039 GNUNET_CRYPTO_hash_cmp(&auth_chain->next->zone, &zone_hash) == 0)
2040 {
2041 /**
2042 * Our zone is next
2043 */
2044 answer_len = strlen(rh->name) + strlen(auth_chain->name)
2045 + strlen(gnunet_tld) + 2;
2046
2047 result = GNUNET_malloc(answer_len);
2048 memset(result, 0, answer_len);
2049 strcpy(result, rh->name);
2050 strcpy(result+strlen(rh->name), ".");
2051 strcpy(result+strlen(rh->name)+1, auth_chain->name);
2052 strcpy(result+strlen(rh->name)+strlen(auth_chain->name)+1, gnunet_tld);
2053 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2054 "Sending non pseudonym shorten result %s\n", result);
2055
2056 send_shorten_response(result, csh);
2057 free_resolver_handle(rh);
2058 GNUNET_free(result);
2059 return;
2060 }
2061
2062 /**
2063 * Continue with next authority
2064 */
2065 new_name = GNUNET_malloc(strlen(rh->name)+
2066 strlen(auth_chain->name) + 2);
2067 memset(new_name, 0, strlen(rh->name)+
2068 strlen(auth_chain->name) + 2);
2069 strcpy(new_name, rh->name);
2070 strcpy(new_name+strlen(rh->name)+1, ".");
2071 strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
2072 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2073 rh->authority_chain_tail,
2074 auth_chain);
2075 GNUNET_free(rh->name);
2076 rh->name = new_name;
2077 GNUNET_free(auth_chain->name);
2078 GNUNET_free(auth_chain);
2079 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2080 &zone_hash,
2081 &rh->authority_chain_head->zone,
2082 &handle_shorten_zone_to_name,
2083 rh);
2084
2085}
2086
2087
2088
2089/**
2090 * Process result from namestore PSEU lookup
2091 * for shorten operation
2092 * FIXME do we need to check for own zone here?
2093 *
2094 * @param cls the client shorten handle
2095 * @param rh the resolver handle
2096 * @param rd_count number of results (0 if none found)
2097 * @param rd data (NULL if none found)
2098 */
2099static void
2100handle_shorten_pseu_ns_result(void* cls,
2101 struct GNUNET_GNS_ResolverHandle *rh,
2102 uint32_t rd_len,
2103 const struct GNUNET_NAMESTORE_RecordData *rd)
2104{
2105 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
2106 struct AuthorityChain *auth_chain;
2107 char* pseu;
2108 char* result;
2109 char* new_name;
2110 size_t answer_len;
2111 int i;
2112
2113 /**
2114 * PSEU found
2115 */
2116 if (rd_len != 0)
2117 {
2118 for (i=0; i < rd_len; i++)
2119 {
2120 if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
2121 {
2122 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2123 "Found PSEU %s\n", (char*) rd[i].data);
2124 break;
2125 }
2126 }
2127
2128 pseu = (char*) rd[i].data;
2129 answer_len = strlen(rh->name) + strlen(pseu) + strlen(gnunet_tld) + 2;
2130 result = GNUNET_malloc(answer_len);
2131 memset(result, 0, answer_len);
2132 strcpy(result, rh->name);
2133 strcpy(result+strlen(rh->name), ".");
2134 strcpy(result+strlen(rh->name)+1, pseu);
2135 strcpy(result+strlen(rh->name)+strlen(pseu)+1, gnunet_tld);
2136
2137 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2138 "Sending shorten result %s\n", result);
2139
2140 send_shorten_response(result, csh);
2141 free_resolver_handle(rh);
2142 GNUNET_free(result);
2143 return;
2144 }
2145
2146 /**
2147 * No PSEU found. Ask DHT if expired.
2148 * Else contunue with next authority
2149 */
2150 if (rh->status & (EXISTS | !EXPIRED))
2151 {
2152 /**
2153 * backtrack
2154 */
2155 auth_chain = rh->authority_chain_head;
2156 new_name = GNUNET_malloc(strlen(rh->name)+
2157 strlen(auth_chain->name) + 2);
2158 memset(new_name, 0, strlen(rh->name)+
2159 strlen(auth_chain->name) + 2);
2160 strcpy(new_name, rh->name);
2161 strcpy(new_name+strlen(rh->name)+1, ".");
2162 strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
2163
2164 GNUNET_free(rh->name);
2165 rh->name = new_name;
2166 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2167 rh->authority_chain_tail,
2168 auth_chain);
2169
2170 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2171 &zone_hash,
2172 &rh->authority_chain_head->zone,
2173 &handle_shorten_zone_to_name,
2174 rh);
2175 return;
2176 }
2177
2178 /**
2179 * Ask DHT
2180 */
2181 rh->authority = rh->authority_chain_head->zone;
2182 rh->proc = &handle_shorten_pseu_dht_result;
2183 resolve_pseu_dht(rh);
2184
2185}
2186
2187
2188
2189/**
2190 * Process result from namestore delegation lookup
2191 * for shorten operation
2192 *
2193 * @param cls the client shorten handle
2194 * @param rh the resolver handle
2195 * @param rd_count number of results (0)
2196 * @param rd data (NULL)
2197 */
2198void
2199handle_shorten_delegation_result(void* cls,
2200 struct GNUNET_GNS_ResolverHandle *rh,
2201 uint32_t rd_count,
2202 const struct GNUNET_NAMESTORE_RecordData *rd)
2203{
2204 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
2205 struct AuthorityChain *auth_chain;
2206 char* result;
2207 size_t answer_len;
2208
2209 /**
2210 * At this point rh->name contains the part of the name
2211 * that we do not have a PKEY in our namestore to resolve.
2212 * The authority chain in the resolver handle is now
2213 * useful to backtrack if needed
2214 */
2215
2216 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2217 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2218
2219 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
2220 &zone_hash) == 0)
2221 {
2222 /**
2223 * This is our zone append .gnunet unless name is empty
2224 * (it shouldn't be, usually FIXME what happens if we
2225 * shorten to our zone to a "" record??)
2226 **/
2227
2228 answer_len = strlen(rh->name) + strlen(gnunet_tld) + 2;
2229 result = GNUNET_malloc(answer_len);
2230 memset(result, 0, answer_len);
2231 strcpy(result, rh->name);
2232 strcpy(result+strlen(rh->name), ".");
2233 strcpy(result+strlen(rh->name)+1, gnunet_tld);
2234
2235 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2236 "Our zone: Sending name as shorten result %s\n", rh->name);
2237
2238 send_shorten_response(result, csh); //FIXME +.gnunet!
2239 free_resolver_handle(rh);
2240 GNUNET_free(result);
2241 return;
2242 }
2243
2244 auth_chain = rh->authority_chain_head;
2245 /* backtrack authorities for pseu */
2246 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2247 &zone_hash, //ours
2248 &auth_chain->zone,
2249 &handle_shorten_zone_to_name,
2250 rh);
2251
2252}
2253
2254typedef void (*ShortenResponseProc) (void* cls, const char* name);
2255
2256/**
2257 * Shorten a given name
2258 *
2259 * @param name the name to shorten
2260 * @param csh the shorten handle of the request
2261 */
2262static void
2263shorten_name(char* name, struct ClientShortenHandle* csh)
2264{
2265
2266 struct GNUNET_GNS_ResolverHandle *rh;
2267
2268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2269 "Starting resolution for %s (type=%d)!\n",
2270 name, GNUNET_GNS_RECORD_PKEY);
2271
2272 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2273 rh->authority = zone_hash;
2274
2275 rh->name = GNUNET_malloc(strlen(name)
2276 - strlen(gnunet_tld) + 1);
2277 memset(rh->name, 0,
2278 strlen(name)-strlen(gnunet_tld) + 1);
2279 memcpy(rh->name, name,
2280 strlen(name)-strlen(gnunet_tld));
2281
2282 csh->name = GNUNET_malloc(strlen(name)
2283 - strlen(gnunet_tld) + 1);
2284 memset(csh->name, 0,
2285 strlen(name)-strlen(gnunet_tld) + 1);
2286 memcpy(csh->name, name,
2287 strlen(name)-strlen(gnunet_tld));
2288
2289 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2290
2291 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2292 rh->authority_chain_tail = rh->authority_chain_head;
2293 rh->authority_chain_head->zone = zone_hash;
2294 rh->proc = &handle_shorten_delegation_result;
2295 rh->proc_cls = (void*)csh;
2296
2297 /* Start delegation resolution in our namestore */
2298 resolve_delegation_ns(rh);
2299
2300}
2301 350
2302/** 351/**
2303 * Send shorten response back to client 352 * Send shorten response back to client
@@ -2306,11 +355,12 @@ shorten_name(char* name, struct ClientShortenHandle* csh)
2306 * @param csh the handle to the shorten request 355 * @param csh the handle to the shorten request
2307 */ 356 */
2308static void 357static void
2309send_shorten_response(const char* name, struct ClientShortenHandle *csh) 358send_shorten_response(void* cls, const char* name)
2310{ 359{
2311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n", 360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
2312 "SHORTEN_RESULT", name); 361 "SHORTEN_RESULT", name);
2313 struct GNUNET_GNS_ClientShortenResultMessage *rmsg; 362 struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
363 struct ClientShortenHandle *csh = (struct ClientShortenHandle *)cls;
2314 364
2315 if (name == NULL) 365 if (name == NULL)
2316 { 366 {
@@ -2354,6 +404,7 @@ static void handle_shorten(void *cls,
2354 404
2355 size_t msg_size = 0; 405 size_t msg_size = 0;
2356 struct ClientShortenHandle *csh; 406 struct ClientShortenHandle *csh;
407 const char* name;
2357 408
2358 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage)) 409 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
2359 { 410 {
@@ -2380,8 +431,16 @@ static void handle_shorten(void *cls,
2380 csh->client = client; 431 csh->client = client;
2381 csh->unique_id = sh_msg->id; 432 csh->unique_id = sh_msg->id;
2382 433
2383 shorten_name((char*)&sh_msg[1], csh); 434 name = (char*)&sh_msg[1];
435 csh->name = GNUNET_malloc(strlen(name)
436 - strlen(GNUNET_GNS_TLD) + 1);
437 memset(csh->name, 0,
438 strlen(name)-strlen(GNUNET_GNS_TLD) + 1);
439 memcpy(csh->name, name,
440 strlen(name)-strlen(GNUNET_GNS_TLD));
2384 441
442 /* Start shortening */
443 gns_resolver_shorten_name(zone_hash, name, &send_shorten_response, csh);
2385} 444}
2386 445
2387 446
@@ -2392,11 +451,12 @@ static void handle_shorten(void *cls,
2392 * @param cah the handle to the get authority request 451 * @param cah the handle to the get authority request
2393 */ 452 */
2394static void 453static void
2395send_get_auth_response(const char* name, struct ClientGetAuthHandle *cah) 454send_get_auth_response(void *cls, const char* name)
2396{ 455{
2397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n", 456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
2398 "GET_AUTH_RESULT", name); 457 "GET_AUTH_RESULT", name);
2399 struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg; 458 struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
459 struct ClientGetAuthHandle *cah = (struct ClientGetAuthHandle *)cls;
2400 460
2401 if (name == NULL) 461 if (name == NULL)
2402 { 462 {
@@ -2429,124 +489,6 @@ send_get_auth_response(const char* name, struct ClientGetAuthHandle *cah)
2429 489
2430} 490}
2431 491
2432/**
2433 * Process result from namestore delegation lookup
2434 * for get authority operation
2435 *
2436 * @param cls the client get auth handle
2437 * @param rh the resolver handle
2438 * @param rd_count number of results (0)
2439 * @param rd data (NULL)
2440 */
2441void
2442handle_get_auth_delegation_result(void* cls,
2443 struct GNUNET_GNS_ResolverHandle *rh,
2444 uint32_t rd_count,
2445 const struct GNUNET_NAMESTORE_RecordData *rd)
2446{
2447 struct ClientGetAuthHandle* cah = (struct ClientGetAuthHandle*) cls;
2448 struct AuthorityChain *auth_chain;
2449 char* result;
2450 size_t answer_len;
2451
2452 /**
2453 * At this point rh->name contains the part of the name
2454 * that we do not have a PKEY in our namestore to resolve.
2455 * The authority chain in the resolver handle is now
2456 * useful to backtrack if needed
2457 */
2458
2459 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2460 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2461
2462 if (is_canonical(rh->name))
2463 {
2464 /**
2465 * We successfully resolved the authority in the ns
2466 * FIXME for our purposes this is fine
2467 * but maybe we want to have an api that also looks
2468 * into the dht (i.e. option in message)
2469 **/
2470 if (strlen(rh->name) > strlen(cah->name))
2471 {
2472 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2473 "Record name longer than original lookup name... odd!\n");
2474 //FIXME to sth here
2475 }
2476
2477
2478 answer_len = strlen(cah->name) - strlen(rh->name) + strlen(gnunet_tld) + 1;
2479 result = GNUNET_malloc(answer_len);
2480 memset(result, 0, answer_len);
2481 strcpy(result, cah->name + strlen(rh->name) + 1);
2482 strcpy(result+strlen(result), gnunet_tld);
2483
2484 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2485 "Got authority result %s\n", result);
2486
2487 send_get_auth_response(result, cah);
2488 free_resolver_handle(rh);
2489 GNUNET_free(result);
2490 return;
2491 }
2492
2493 auth_chain = rh->authority_chain_head;
2494 /* backtrack authorities for pseu */
2495 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2496 &zone_hash, //ours
2497 &auth_chain->zone,
2498 &handle_shorten_zone_to_name,
2499 rh);
2500
2501}
2502
2503
2504/**
2505 * Get authority for a given name
2506 *
2507 * @param name the name to shorten
2508 * @param csh the shorten handle of the request
2509 */
2510static void
2511get_authority(char* name, struct ClientGetAuthHandle* cah)
2512{
2513
2514 struct GNUNET_GNS_ResolverHandle *rh;
2515
2516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2517 "Starting authority resolution for %s (type=%d)!\n",
2518 name, GNUNET_GNS_RECORD_PKEY);
2519
2520 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2521 rh->authority = zone_hash;
2522
2523 rh->name = GNUNET_malloc(strlen(name)
2524 - strlen(gnunet_tld) + 1);
2525 memset(rh->name, 0,
2526 strlen(name)-strlen(gnunet_tld) + 1);
2527 memcpy(rh->name, name,
2528 strlen(name)-strlen(gnunet_tld));
2529
2530 cah->name = GNUNET_malloc(strlen(name)
2531 - strlen(gnunet_tld) + 1);
2532 memset(cah->name, 0,
2533 strlen(name)-strlen(gnunet_tld) + 1);
2534 memcpy(cah->name, name,
2535 strlen(name)-strlen(gnunet_tld));
2536
2537 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2538
2539 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2540 rh->authority_chain_tail = rh->authority_chain_head;
2541 rh->authority_chain_head->zone = zone_hash;
2542 rh->proc = &handle_get_auth_delegation_result;
2543 rh->proc_cls = (void*)cah;
2544
2545 /* Start delegation resolution in our namestore */
2546 resolve_delegation_ns(rh);
2547
2548}
2549
2550 492
2551/** 493/**
2552 * Handle a get authority message from the api 494 * Handle a get authority message from the api
@@ -2563,6 +505,7 @@ static void handle_get_authority(void *cls,
2563 505
2564 size_t msg_size = 0; 506 size_t msg_size = 0;
2565 struct ClientGetAuthHandle *cah; 507 struct ClientGetAuthHandle *cah;
508 const char* name;
2566 509
2567 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage)) 510 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
2568 { 511 {
@@ -2589,8 +532,16 @@ static void handle_get_authority(void *cls,
2589 cah->client = client; 532 cah->client = client;
2590 cah->unique_id = sh_msg->id; 533 cah->unique_id = sh_msg->id;
2591 534
2592 get_authority((char*)&sh_msg[1], cah); 535 name = (char*)&sh_msg[1];
536 cah->name = GNUNET_malloc(strlen(name)
537 - strlen(GNUNET_GNS_TLD) + 1);
538 memset(cah->name, 0,
539 strlen(name)-strlen(GNUNET_GNS_TLD) + 1);
540 memcpy(cah->name, name,
541 strlen(name)-strlen(GNUNET_GNS_TLD));
2593 542
543 /* Start delegation resolution in our namestore */
544 gns_resolver_get_authority(zone_hash, name, &send_get_auth_response, cah);
2594} 545}
2595 546
2596 547
@@ -2603,9 +554,9 @@ static void handle_get_authority(void *cls,
2603 * @param rd the record data 554 * @param rd the record data
2604 */ 555 */
2605static void 556static void
2606reply_to_client(void* cls, struct GNUNET_GNS_ResolverHandle *rh, 557send_lookup_response(void* cls,
2607 uint32_t rd_count, 558 uint32_t rd_count,
2608 const struct GNUNET_NAMESTORE_RecordData *rd) 559 const struct GNUNET_NAMESTORE_RecordData *rd)
2609{ 560{
2610 struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls; 561 struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
2611 struct GNUNET_GNS_ClientLookupResultMessage *rmsg; 562 struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
@@ -2630,63 +581,12 @@ reply_to_client(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
2630 GNUNET_NO); 581 GNUNET_NO);
2631 GNUNET_SERVER_receive_done (clh->client, GNUNET_OK); 582 GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
2632 583
2633 GNUNET_free(rh->proc_cls);
2634 free_resolver_handle(rh);
2635 GNUNET_free(rmsg); 584 GNUNET_free(rmsg);
2636 GNUNET_free(clh->name); 585 GNUNET_free(clh->name);
2637 GNUNET_free(clh); 586 GNUNET_free(clh);
2638 587
2639} 588}
2640 589
2641/**
2642 * Lookup a given name
2643 *
2644 * @param name the name to looku[
2645 * @param clh the client lookup handle
2646 */
2647static void
2648lookup_name(char* name, struct ClientLookupHandle* clh)
2649{
2650
2651 struct GNUNET_GNS_ResolverHandle *rh;
2652 struct RecordLookupHandle* rlh;
2653
2654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2655 "Starting resolution for %s (type=%d)!\n",
2656 name, clh->type);
2657
2658 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2659 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2660
2661 rh->authority = zone_hash;
2662
2663 rlh->record_type = clh->type;
2664 rlh->name = clh->name;
2665 rlh->proc = &reply_to_client;
2666 rlh->proc_cls = clh;
2667
2668 rh->proc_cls = rlh;
2669
2670 rh->name = GNUNET_malloc(strlen(name)
2671 - strlen(gnunet_tld) + 1);
2672 memset(rh->name, 0,
2673 strlen(name)-strlen(gnunet_tld) + 1);
2674 memcpy(rh->name, name,
2675 strlen(name)-strlen(gnunet_tld));
2676
2677 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2678
2679 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2680 rh->authority_chain_head->prev = NULL;
2681 rh->authority_chain_head->next = NULL;
2682 rh->authority_chain_tail = rh->authority_chain_head;
2683 rh->authority_chain_head->zone = zone_hash;
2684
2685 /* Start resolution in our zone */
2686 rh->proc = &process_delegation_ns;
2687 resolve_delegation_ns(rh);
2688}
2689
2690 590
2691/** 591/**
2692 * Handle lookup requests from client 592 * Handle lookup requests from client
@@ -2733,7 +633,8 @@ handle_lookup(void *cls,
2733 clh->unique_id = sh_msg->id; 633 clh->unique_id = sh_msg->id;
2734 clh->type = ntohl(sh_msg->type); 634 clh->type = ntohl(sh_msg->type);
2735 635
2736 lookup_name((char*)&sh_msg[1], clh); 636 gns_resolver_lookup_record(zone_hash, clh->type, (char*)&sh_msg[1],
637 &send_lookup_response, clh);
2737} 638}
2738 639
2739 640
@@ -2778,24 +679,17 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
2778 GNUNET_free(keyfile); 679 GNUNET_free(keyfile);
2779 680
2780 681
2781 dns_handle = NULL;
2782 if (GNUNET_YES == 682 if (GNUNET_YES ==
2783 GNUNET_CONFIGURATION_get_value_yesno (c, "gns", 683 GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
2784 "HIJACK_DNS")) 684 "HIJACK_DNS"))
2785 { 685 {
2786 GNUNET_log(GNUNET_ERROR_TYPE_INFO, 686 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2787 "DNS hijacking enabled... connecting to service.\n"); 687 "DNS hijacking enabled... connecting to service.\n");
2788 /** 688
2789 * Do gnunet dns init here 689 if (gns_interceptor_init(zone_hash, c) == GNUNET_SYSERR)
2790 */
2791 dns_handle = GNUNET_DNS_connect(c,
2792 GNUNET_DNS_FLAG_PRE_RESOLUTION,
2793 &handle_dns_request, /* rh */
2794 NULL); /* Closure */
2795 if (NULL == dns_handle)
2796 { 690 {
2797 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 691 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2798 "Failed to connect to the dnsservice!\n"); 692 "Failed to enable the dns interceptor!\n");
2799 } 693 }
2800 } 694 }
2801 695
diff --git a/src/gns/gnunet-service-gns_interceptor.c b/src/gns/gnunet-service-gns_interceptor.c
new file mode 100644
index 000000000..1a14eb96e
--- /dev/null
+++ b/src/gns/gnunet-service-gns_interceptor.c
@@ -0,0 +1,327 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
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.
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 General Public License for more details.
14
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.
19*/
20
21/**
22 *
23 * @file gns/gns_interceptor.c
24 * @brief GNUnet GNS interceptor logic
25 * @author Martin Schanzenbach
26 */
27#include "platform.h"
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-service-gns_resolver.h"
33#include "gns.h"
34
35#define MAX_DNS_LABEL_LENGTH 63
36
37/**
38 * Handle to a DNS intercepted
39 * reslution request
40 */
41struct InterceptLookupHandle
42{
43 /* the request handle to reply to */
44 struct GNUNET_DNS_RequestHandle *request_handle;
45
46 /* the dns parser packet received */
47 struct GNUNET_DNSPARSER_Packet *packet;
48
49 /* the query parsed from the packet */
50 struct GNUNET_DNSPARSER_Query *query;
51};
52
53
54/**
55 * Our handle to the DNS handler library
56 */
57struct GNUNET_DNS_Handle *dns_handle;
58
59/**
60 * The root zone for this interceptor
61 */
62static GNUNET_HashCode our_zone;
63
64/**
65 * Reply to dns request with the result from our lookup.
66 *
67 * @param cls the closure to the request (an InterceptLookupHandle)
68 * @param rh the request handle of the lookup
69 * @param rd_count the number of records to return
70 * @param rd the record data
71 */
72static void
73reply_to_dns(void* cls, uint32_t rd_count,
74 const struct GNUNET_NAMESTORE_RecordData *rd)
75{
76 int i;
77 size_t len;
78 int ret;
79 char *buf;
80 struct InterceptLookupHandle* ilh = (struct InterceptLookupHandle*)cls;
81 struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
82 unsigned int num_answers = 0;
83
84
85 /**
86 * Put records in the DNS packet and modify it
87 * to a response
88 */
89 for (i=0; i < rd_count; i++)
90 {
91 if (rd[i].record_type == ilh->query->type)
92 num_answers++;
93 }
94
95 struct GNUNET_DNSPARSER_Record answer_records[num_answers];
96 struct GNUNET_DNSPARSER_Record additional_records[rd_count-(num_answers)];
97 packet->answers = answer_records;
98 packet->additional_records = additional_records;
99
100 for (i=0; i < rd_count; i++)
101 {
102 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
103 "Adding type %d to DNS response\n", rd[i].record_type);
104 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", ilh->query->name);
105 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
106 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
107
108 if (rd[i].record_type == ilh->query->type)
109 {
110 num_answers++;
111 answer_records[i].name = ilh->query->name;
112 answer_records[i].type = rd[i].record_type;
113 answer_records[i].data.raw.data_len = rd[i].data_size;
114 answer_records[i].data.raw.data = (char*)rd[i].data;
115 answer_records[i].expiration_time = rd[i].expiration;
116 answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
117 }
118 else
119 {
120 additional_records[i].name = ilh->query->name;
121 additional_records[i].type = rd[i].record_type;
122 additional_records[i].data.raw.data_len = rd[i].data_size;
123 additional_records[i].data.raw.data = (char*)rd[i].data;
124 additional_records[i].expiration_time = rd[i].expiration;
125 additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
126 }
127 }
128
129 packet->num_answers = num_answers;
130 packet->num_additional_records = rd_count-(num_answers);
131
132 packet->flags.authoritative_answer = 1;
133
134 if (rd == NULL)
135 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
136 else
137 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
138
139 packet->flags.query_or_response = 1;
140
141
142 /**
143 * Reply to DNS
144 */
145 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
146 "Building DNS response\n");
147 ret = GNUNET_DNSPARSER_pack (packet,
148 1024, /* FIXME magic from dns redirector */
149 &buf,
150 &len);
151 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
152 "Built DNS response! (ret=%d,len=%d)\n", ret, len);
153 if (ret == GNUNET_OK)
154 {
155 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
156 "Answering DNS request\n");
157 GNUNET_DNS_request_answer(ilh->request_handle,
158 len,
159 buf);
160
161 GNUNET_free(buf);
162 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
163 }
164 else
165 {
166 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
167 "Error building DNS response! (ret=%d)", ret);
168 }
169
170 packet->num_answers = 0;
171 packet->answers = NULL;
172 packet->num_additional_records = 0;
173 packet->additional_records = NULL;
174 GNUNET_DNSPARSER_free_packet(packet);
175 //FIXME free resolver handle in resp functions in resolver!
176 //GNUNET_free((struct RecordLookupHandle*)rh->proc_cls);
177 //free_resolver_handle(rh);
178 GNUNET_free(ilh);
179}
180
181
182/**
183 * Entry point for name resolution
184 * Setup a new query and try to resolve
185 *
186 * @param request the request handle of the DNS request from a client
187 * @param p the DNS query packet we received
188 * @param q the DNS query we received parsed from p
189 */
190static void
191start_resolution_for_dns(struct GNUNET_DNS_RequestHandle *request,
192 struct GNUNET_DNSPARSER_Packet *p,
193 struct GNUNET_DNSPARSER_Query *q)
194{
195 struct InterceptLookupHandle* ilh;
196
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198 "Starting resolution for %s (type=%d)!\n",
199 q->name, q->type);
200
201 ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle));
202 ilh->packet = p;
203 ilh->query = q;
204 ilh->request_handle = request;
205
206 /* Start resolution in our zone */
207 gns_resolver_lookup_record(our_zone, q->type, q->name, &reply_to_dns, ilh);
208}
209
210
211
212/**
213 * The DNS request handler
214 * Called for every incoming DNS request.
215 *
216 * @param cls closure
217 * @param rh request handle to user for reply
218 * @param request_length number of bytes in request
219 * @param request udp payload of the DNS request
220 */
221static void
222handle_dns_request(void *cls,
223 struct GNUNET_DNS_RequestHandle *rh,
224 size_t request_length,
225 const char *request)
226{
227 struct GNUNET_DNSPARSER_Packet *p;
228 int i;
229 char *tldoffset;
230
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
232 p = GNUNET_DNSPARSER_parse (request, request_length);
233
234 if (NULL == p)
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
237 "Received malformed DNS packet, leaving it untouched\n");
238 GNUNET_DNS_request_forward (rh);
239 GNUNET_DNSPARSER_free_packet (p);
240 return;
241 }
242
243 /**
244 * Check tld and decide if we or
245 * legacy dns is responsible
246 *
247 * FIXME now in theory there could be more than 1 query in the request
248 * but if this is case we get into trouble:
249 * either we query the GNS or the DNS. We cannot do both!
250 * So I suggest to either only allow a single query per request or
251 * only allow GNS or DNS requests.
252 * The way it is implemented here now is buggy and will lead to erratic
253 * behaviour (if multiple queries are present).
254 */
255 if (p->num_queries == 0)
256 {
257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
258 "No Queries in DNS packet... forwarding\n");
259 GNUNET_DNS_request_forward (rh);
260 GNUNET_DNSPARSER_free_packet(p);
261 return;
262 }
263
264 if (p->num_queries > 1)
265 {
266 /* Note: We could also look for .gnunet */
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 ">1 queriy in DNS packet... odd. We only process #1\n");
269 }
270
271
272 /**
273 * Check for .gnunet
274 */
275 tldoffset = p->queries[0].name + strlen(p->queries[0].name) - 1;
276
277 for (i=0; i<strlen(p->queries[0].name); i++)
278 {
279 if (*(tldoffset-i) == '.')
280 break;
281 }
282
283 if ((i==strlen(GNUNET_GNS_TLD)-1)
284 && (0 == strcmp(tldoffset-i, GNUNET_GNS_TLD)))
285 {
286 start_resolution_for_dns(rh, p, p->queries);
287 }
288 else
289 {
290 /**
291 * This request does not concern us. Forward to real DNS.
292 */
293 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
294 "Request for %s is forwarded to DNS\n", p->queries[0].name);
295 GNUNET_DNS_request_forward (rh);
296 GNUNET_DNSPARSER_free_packet (p);
297 }
298
299}
300
301
302int
303gns_interceptor_init(GNUNET_HashCode zone,
304 const struct GNUNET_CONFIGURATION_Handle *c)
305{
306 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
307 "DNS hijacking enabled... connecting to service.\n");
308
309 our_zone = zone;
310 /**
311 * Do gnunet dns init here
312 */
313 dns_handle = GNUNET_DNS_connect(c,
314 GNUNET_DNS_FLAG_PRE_RESOLUTION,
315 &handle_dns_request, /* rh */
316 NULL); /* Closure */
317 if (NULL == dns_handle)
318 {
319 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
320 "Failed to connect to the dnsservice!\n");
321 return GNUNET_SYSERR;
322 }
323
324 return GNUNET_YES;
325}
326
327/* end of gns_interceptor.c */
diff --git a/src/gns/gnunet-service-gns_interceptor.h b/src/gns/gnunet-service-gns_interceptor.h
new file mode 100644
index 000000000..03b91856e
--- /dev/null
+++ b/src/gns/gnunet-service-gns_interceptor.h
@@ -0,0 +1,18 @@
1#ifndef GNUNET_GNS_INTERCEPTOR_H
2#define GNUNET_GNS_INTERCEPTOR_H
3
4/**
5 * Initialize dns interceptor
6 *
7 * @param zone the zone
8 * @param c the configuration
9 * @return GNUNET_YES on success GNUNET_SYSERR on error
10 */
11int
12gns_interceptor_init(GNUNET_HashCode zone,
13 const struct GNUNET_CONFIGURATION_Handle *c);
14
15void
16gns_interceptor_stop(void){};
17
18#endif
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
new file mode 100644
index 000000000..53fdcc463
--- /dev/null
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -0,0 +1,1712 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
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.
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 General Public License for more details.
14
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.
19*/
20
21/**
22 *
23 *
24 * @file gns/gns_resolver.c
25 * @brief GNUnet GNS service
26 * @author Martin Schanzenbach
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_dns_service.h"
32#include "gnunet_dht_service.h"
33#include "gnunet_namestore_service.h"
34#include "gnunet_dns_service.h"
35#include "gnunet_dnsparser_lib.h"
36#include "gnunet_gns_service.h"
37#include "block_gns.h"
38#include "gns.h"
39#include "gnunet-service-gns_resolver.h"
40
41#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
42#define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
43#define DHT_GNS_REPLICATION_LEVEL 5
44#define MAX_DNS_LABEL_LENGTH 63
45
46
47/**
48 * Our handle to the namestore service
49 * FIXME maybe need a second handle for iteration
50 */
51struct GNUNET_NAMESTORE_Handle *namestore_handle;
52
53struct GNUNET_DHT_Handle *dht_handle;
54
55static void
56connect_to_dht()
57{
58 //FIXME
59}
60
61/**
62 * Helper function to free resolver handle
63 *
64 * @rh the handle to free
65 */
66static void
67free_resolver_handle(struct ResolverHandle* rh)
68{
69 struct AuthorityChain *ac;
70 struct AuthorityChain *ac_next;
71
72 if (NULL == rh)
73 return;
74
75 GNUNET_free_non_null (rh->name);
76 GNUNET_free_non_null (rh->authority_name);
77
78 ac = rh->authority_chain_head;
79
80 while (NULL != ac)
81 {
82 ac_next = ac->next;
83 GNUNET_free_non_null (ac->name);
84 GNUNET_free(ac);
85 ac = ac_next;
86 }
87 GNUNET_free(rh);
88}
89
90
91/**
92 * Callback when record data is put into namestore
93 *
94 * @param cls the closure
95 * @param success GNUNET_OK on success
96 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
97 */
98void
99on_namestore_record_put_result(void *cls,
100 int32_t success,
101 const char *emsg)
102{
103 if (GNUNET_NO == success)
104 {
105 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
106 return;
107 }
108 else if (GNUNET_YES == success)
109 {
110 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
111 "records successfully put in namestore\n");
112 return;
113 }
114
115 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
116 "Error putting records into namestore: %s\n", emsg);
117}
118
119
120/**
121 * Handle timeout for DHT requests
122 *
123 * @param cls the request handle as closure
124 * @param tc the task context
125 */
126static void
127dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
128{
129 struct ResolverHandle *rh = cls;
130
131 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
132 "dht lookup for query %s timed out.\n",
133 rh->name);
134
135 GNUNET_DHT_get_stop (rh->get_handle);
136 rh->proc(rh->proc_cls, rh, 0, NULL);
137}
138
139
140/**
141 * Function called when we get a result from the dht
142 * for our record query
143 *
144 * @param cls the request handle
145 * @param exp lifetime
146 * @param key the key the record was stored under
147 * @param get_path get path
148 * @param get_path_length get path length
149 * @param put_path put path
150 * @param put_path_length put path length
151 * @param type the block type
152 * @param size the size of the record
153 * @param data the record data
154 */
155static void
156process_record_result_dht(void* cls,
157 struct GNUNET_TIME_Absolute exp,
158 const GNUNET_HashCode * key,
159 const struct GNUNET_PeerIdentity *get_path,
160 unsigned int get_path_length,
161 const struct GNUNET_PeerIdentity *put_path,
162 unsigned int put_path_length,
163 enum GNUNET_BLOCK_Type type,
164 size_t size, const void *data)
165{
166 struct ResolverHandle *rh;
167 struct RecordLookupHandle *rlh;
168 struct GNSNameRecordBlock *nrb;
169 uint32_t num_records;
170 char* name = NULL;
171 char* rd_data = (char*)data;
172 int i;
173 int rd_size;
174
175 GNUNET_HashCode zone, name_hash;
176 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
177
178 if (data == NULL)
179 return;
180
181 //FIXME maybe check expiration here, check block type
182
183 rh = (struct ResolverHandle *)cls;
184 rlh = (struct RecordLookupHandle *) rh->proc_cls;
185 nrb = (struct GNSNameRecordBlock*)data;
186
187 /* stop lookup and timeout task */
188 GNUNET_DHT_get_stop (rh->get_handle);
189 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
190
191 rh->get_handle = NULL;
192 name = (char*)&nrb[1];
193 num_records = ntohl(nrb->rd_count);
194 {
195 struct GNUNET_NAMESTORE_RecordData rd[num_records];
196
197 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
198 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
199
200 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
201 rd_data,
202 num_records,
203 rd))
204 {
205 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
206 return;
207 }
208
209 for (i=0; i<num_records; i++)
210 {
211 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
212 "Got name: %s (wanted %s)\n", name, rh->name);
213 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
214 "Got type: %d\n",
215 rd[i].record_type);
216 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
217 "Got data length: %d\n", rd[i].data_size);
218 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
219 "Got flag %d\n", rd[i].flags);
220
221 if ((strcmp(name, rh->name) == 0) &&
222 (rd[i].record_type == rlh->record_type))
223 {
224 rh->answered++;
225 }
226
227 }
228
229 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
230 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
231
232 /**
233 * FIXME check pubkey against existing key in namestore?
234 * https://gnunet.org/bugs/view.php?id=2179
235 */
236
237 /* Save to namestore */
238 GNUNET_NAMESTORE_record_put (namestore_handle,
239 &nrb->public_key,
240 name,
241 exp,
242 num_records,
243 rd,
244 &nrb->signature,
245 &on_namestore_record_put_result, //cont
246 NULL); //cls
247
248 if (rh->answered)
249 rh->proc(rh->proc_cls, rh, num_records, rd);
250 else
251 rh->proc(rh->proc_cls, rh, 0, NULL);
252 }
253
254}
255
256
257/**
258 * Start DHT lookup for a (name -> query->record_type) record in
259 * rh->authority's zone
260 *
261 * @param rh the pending gns query context
262 */
263static void
264resolve_record_dht(struct ResolverHandle *rh)
265{
266 uint32_t xquery;
267 GNUNET_HashCode name_hash;
268 GNUNET_HashCode lookup_key;
269 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
270 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
271
272 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
273 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
274 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
275
276 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
277 "starting dht lookup for %s with key: %s\n",
278 rh->name, (char*)&lookup_key_string);
279
280 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
281 &dht_lookup_timeout, rh);
282
283 xquery = htonl(rlh->record_type);
284 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
285 DHT_OPERATION_TIMEOUT,
286 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
287 &lookup_key,
288 DHT_GNS_REPLICATION_LEVEL,
289 GNUNET_DHT_RO_NONE,
290 &xquery,
291 sizeof(xquery),
292 &process_record_result_dht,
293 rh);
294
295}
296
297
298/**
299 * Namestore calls this function if we have record for this name.
300 * (or with rd_count=0 to indicate no matches)
301 *
302 * @param cls the pending query
303 * @param key the key of the zone we did the lookup
304 * @param expiration expiration date of the namestore entry
305 * @param name the name for which we need an authority
306 * @param rd_count the number of records with 'name'
307 * @param rd the record data
308 * @param signature the signature of the authority for the record data
309 */
310static void
311process_record_result_ns(void* cls,
312 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
313 struct GNUNET_TIME_Absolute expiration,
314 const char *name, unsigned int rd_count,
315 const struct GNUNET_NAMESTORE_RecordData *rd,
316 const struct GNUNET_CRYPTO_RsaSignature *signature)
317{
318 struct ResolverHandle *rh;
319 struct RecordLookupHandle *rlh;
320 struct GNUNET_TIME_Relative remaining_time;
321 GNUNET_HashCode zone;
322
323 rh = (struct ResolverHandle *) cls;
324 rlh = (struct RecordLookupHandle *)rh->proc_cls;
325 GNUNET_CRYPTO_hash(key,
326 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
327 &zone);
328 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
329
330 rh->status = 0;
331
332 if (name != NULL)
333 {
334 rh->status |= EXISTS;
335 }
336
337 if (remaining_time.rel_value == 0)
338 {
339 rh->status |= EXPIRED;
340 }
341
342 if (rd_count == 0)
343 {
344 /**
345 * Lookup terminated and no results
346 */
347 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
348 "Namestore lookup for %s terminated without results\n", name);
349
350 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
351 "Record %s unknown in namestore\n",
352 rh->name);
353 /**
354 * Our zone and no result? Cannot resolve TT
355 */
356 rh->proc(rh->proc_cls, rh, 0, NULL);
357 return;
358
359 }
360 else
361 {
362
363 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
364 "Processing additional result %s from namestore\n", name);
365 int i;
366 for (i=0; i<rd_count;i++)
367 {
368
369 if (rd[i].record_type != rlh->record_type)
370 continue;
371
372 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
373 == 0)
374 {
375 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
376 "This record is expired. Skipping\n");
377 continue;
378 }
379
380 rh->answered++;
381
382 }
383
384 /**
385 * no answers found
386 */
387 if (rh->answered == 0)
388 {
389 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
390 "No answers found. This is odd!\n");
391 rh->proc(rh->proc_cls, rh, 0, NULL);
392 return;
393 }
394
395 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
396 rh->answered);
397
398 rh->proc(rh->proc_cls, rh, rd_count, rd);
399 }
400}
401
402
403/**
404 * The final phase of resolution.
405 * rh->name is a name that is canonical and we do not have a delegation.
406 * Query namestore for this record
407 *
408 * @param rh the pending lookup
409 */
410static void
411resolve_record_ns(struct ResolverHandle *rh)
412{
413 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
414
415 /**
416 * Try to resolve this record in our namestore.
417 * The name to resolve is now in rh->authority_name
418 * since we tried to resolve it to an authority
419 * and failed.
420 **/
421 GNUNET_NAMESTORE_lookup_record(namestore_handle,
422 &rh->authority,
423 rh->name,
424 rlh->record_type,
425 &process_record_result_ns,
426 rh);
427}
428
429
430/**
431 * Handle timeout for DHT requests
432 *
433 * @param cls the request handle as closure
434 * @param tc the task context
435 */
436static void
437dht_authority_lookup_timeout(void *cls,
438 const struct GNUNET_SCHEDULER_TaskContext *tc)
439{
440 struct ResolverHandle *rh = cls;
441
442 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
443 "dht lookup for query %s timed out.\n",
444 rh->name);
445
446 GNUNET_DHT_get_stop (rh->get_handle);
447 if (strcmp(rh->name, "") == 0)
448 {
449 /*
450 * promote authority back to name and try to resolve record
451 */
452 strcpy(rh->name, rh->authority_name);
453 }
454 rh->proc(rh->proc_cls, rh, 0, NULL);
455}
456
457/* Prototype */
458static void resolve_delegation_dht(struct ResolverHandle *rh);
459
460/**
461 * Function called when we get a result from the dht
462 * for our query. Recursively tries to resolve authorities
463 * for name in DHT.
464 *
465 * @param cls the request handle
466 * @param exp lifetime
467 * @param key the key the record was stored under
468 * @param get_path get path
469 * @param get_path_length get path length
470 * @param put_path put path
471 * @param put_path_length put path length
472 * @param type the block type
473 * @param size the size of the record
474 * @param data the record data
475 */
476static void
477process_delegation_result_dht(void* cls,
478 struct GNUNET_TIME_Absolute exp,
479 const GNUNET_HashCode * key,
480 const struct GNUNET_PeerIdentity *get_path,
481 unsigned int get_path_length,
482 const struct GNUNET_PeerIdentity *put_path,
483 unsigned int put_path_length,
484 enum GNUNET_BLOCK_Type type,
485 size_t size, const void *data)
486{
487 struct ResolverHandle *rh;
488 struct GNSNameRecordBlock *nrb;
489 uint32_t num_records;
490 char* name = NULL;
491 char* rd_data = (char*) data;
492 int i;
493 int rd_size;
494 GNUNET_HashCode zone, name_hash;
495
496 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
497
498 if (data == NULL)
499 return;
500
501 //FIXME check expiration?
502
503 rh = (struct ResolverHandle *)cls;
504 nrb = (struct GNSNameRecordBlock*)data;
505
506 /* stop dht lookup and timeout task */
507 GNUNET_DHT_get_stop (rh->get_handle);
508 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
509
510 rh->get_handle = NULL;
511 num_records = ntohl(nrb->rd_count);
512 name = (char*)&nrb[1];
513 {
514 struct GNUNET_NAMESTORE_RecordData rd[num_records];
515
516 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
517 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
518
519 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
520 rd_data,
521 num_records,
522 rd))
523 {
524 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
525 return;
526 }
527
528 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
529 "Got name: %s (wanted %s)\n", name, rh->authority_name);
530 for (i=0; i<num_records; i++)
531 {
532
533 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
534 "Got name: %s (wanted %s)\n", name, rh->authority_name);
535 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
536 "Got type: %d (wanted %d)\n",
537 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
538 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
539 "Got data length: %d\n", rd[i].data_size);
540 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
541 "Got flag %d\n", rd[i].flags);
542
543 if ((strcmp(name, rh->authority_name) == 0) &&
544 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
545 {
546 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
547 rh->answered = 1;
548 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
549 struct AuthorityChain *auth =
550 GNUNET_malloc(sizeof(struct AuthorityChain));
551 auth->zone = rh->authority;
552 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
553 memset(auth->name, 0, strlen(rh->authority_name)+1);
554 strcpy(auth->name, rh->authority_name);
555 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
556 rh->authority_chain_tail,
557 auth);
558 }
559
560 }
561
562
563 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
564 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
565
566 /* Save to namestore */
567 if (0 != GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_tail->zone, &zone))
568 {
569 GNUNET_NAMESTORE_record_put (namestore_handle,
570 &nrb->public_key,
571 name,
572 exp,
573 num_records,
574 rd,
575 &nrb->signature,
576 &on_namestore_record_put_result, //cont
577 NULL); //cls
578 }
579 }
580
581 if (rh->answered)
582 {
583 rh->answered = 0;
584 /**
585 * delegate
586 * FIXME in this case. should we ask namestore again?
587 */
588 if (strcmp(rh->name, "") == 0)
589 rh->proc(rh->proc_cls, rh, 0, NULL);
590 else
591 resolve_delegation_dht(rh);
592 return;
593 }
594
595 /**
596 * should never get here unless false dht key/put
597 * block plugin should handle this
598 **/
599 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup error!\n");
600 GNUNET_break(0);
601}
602
603
604/**
605 * Process DHT lookup result for record.
606 *
607 * @param cls the closure
608 * @param rh resolver handle
609 * @param rd_count number of results (always 0)
610 * @param rd record data (always NULL)
611 */
612static void
613handle_record_dht(void* cls, struct ResolverHandle *rh,
614 unsigned int rd_count,
615 const struct GNUNET_NAMESTORE_RecordData *rd)
616{
617 struct RecordLookupHandle* rlh;
618 rlh = (struct RecordLookupHandle*)cls;
619 if (rd_count == 0)
620 {
621 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
622 "No records for %s found in DHT. Aborting\n",
623 rh->name);
624 /* give up, cannot resolve */
625 rlh->proc(rlh->proc_cls, 0, NULL);
626 return;
627 }
628
629 /* results found yay */
630 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
631 "Record resolved from namestore!");
632 rlh->proc(rlh->proc_cls, rd_count, rd);
633
634}
635
636
637/**
638 * Process namestore lookup result for record.
639 *
640 * @param cls the closure
641 * @param rh resolver handle
642 * @param rd_count number of results (always 0)
643 * @param rd record data (always NULL)
644 */
645static void
646handle_record_ns(void* cls, struct ResolverHandle *rh,
647 unsigned int rd_count,
648 const struct GNUNET_NAMESTORE_RecordData *rd)
649{
650 struct RecordLookupHandle* rlh;
651 rlh = (struct RecordLookupHandle*) cls;
652 if (rd_count == 0)
653 {
654 /* ns entry expired. try dht */
655 if (rh->status & (EXPIRED | !EXISTS))
656 {
657 rh->proc = &handle_record_dht;
658 resolve_record_dht(rh);
659 return;
660 }
661 /* give up, cannot resolve */
662 rlh->proc(rlh->proc_cls, 0, NULL);
663 return;
664 }
665
666 /* results found yay */
667 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
668 "Record resolved from namestore!");
669 rlh->proc(rlh->proc_cls, rd_count, rd);
670
671}
672
673
674/**
675 * Determine if this name is canonical.
676 * i.e.
677 * a.b.gnunet = not canonical
678 * a = canonical
679 *
680 * @param name the name to test
681 * @return 1 if canonical
682 */
683static int
684is_canonical(char* name)
685{
686 uint32_t len = strlen(name);
687 int i;
688
689 for (i=0; i<len; i++)
690 {
691 if (*(name+i) == '.')
692 return 0;
693 }
694 return 1;
695}
696
697/**
698 * Move one level up in the domain hierarchy and return the
699 * passed top level domain.
700 *
701 * @param name the domain
702 * @param dest the destination where the tld will be put
703 */
704void
705pop_tld(char* name, char* dest)
706{
707 uint32_t len;
708
709 if (is_canonical(name))
710 {
711 strcpy(dest, name);
712 strcpy(name, "");
713 return;
714 }
715
716 for (len = strlen(name); len > 0; len--)
717 {
718 if (*(name+len) == '.')
719 break;
720 }
721
722 //Was canonical?
723 if (len == 0)
724 return;
725
726 name[len] = '\0';
727
728 strcpy(dest, (name+len+1));
729}
730
731/**
732 * DHT resolution for delegation finished. Processing result.
733 *
734 * @param cls the closure
735 * @param rh resolver handle
736 * @param rd_count number of results (always 0)
737 * @param rd record data (always NULL)
738 */
739static void
740handle_delegation_dht(void* cls, struct ResolverHandle *rh,
741 unsigned int rd_count,
742 const struct GNUNET_NAMESTORE_RecordData *rd)
743{
744 struct RecordLookupHandle* rlh;
745 rlh = (struct RecordLookupHandle*) cls;
746
747 if (strcmp(rh->name, "") == 0)
748 {
749 /* We resolved full name for delegation. resolving record */
750 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
751 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
752 rh->proc = &handle_record_ns;
753 resolve_record_ns(rh);
754 return;
755 }
756
757 /**
758 * we still have some left
759 **/
760 if (is_canonical(rh->name))
761 {
762 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
763 "Resolving canonical record %s in ns\n", rh->name);
764 rh->proc = &handle_record_ns;
765 resolve_record_ns(rh);
766 return;
767 }
768 /* give up, cannot resolve */
769 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
770 "Cannot fully resolve delegation for %s via DHT!\n",
771 rh->name);
772 rlh->proc(rlh->proc_cls, 0, NULL);
773}
774
775
776/**
777 * Start DHT lookup for a name -> PKEY (compare NS) record in
778 * rh->authority's zone
779 *
780 * @param rh the pending gns query
781 * @param name the name of the PKEY record
782 */
783static void
784resolve_delegation_dht(struct ResolverHandle *rh)
785{
786 uint32_t xquery;
787 GNUNET_HashCode name_hash;
788 GNUNET_HashCode lookup_key;
789
790 GNUNET_CRYPTO_hash(rh->authority_name,
791 strlen(rh->authority_name),
792 &name_hash);
793 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
794
795 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
796 &dht_authority_lookup_timeout,
797 rh);
798
799 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
800
801 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
802 DHT_OPERATION_TIMEOUT,
803 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
804 &lookup_key,
805 DHT_GNS_REPLICATION_LEVEL,
806 GNUNET_DHT_RO_NONE,
807 &xquery,
808 sizeof(xquery),
809 &process_delegation_result_dht,
810 rh);
811
812}
813
814
815/**
816 * Namestore resolution for delegation finished. Processing result.
817 *
818 * @param cls the closure
819 * @param rh resolver handle
820 * @param rd_count number of results (always 0)
821 * @param rd record data (always NULL)
822 */
823static void
824handle_delegation_ns(void* cls, struct ResolverHandle *rh,
825 unsigned int rd_count,
826 const struct GNUNET_NAMESTORE_RecordData *rd)
827{
828 struct RecordLookupHandle* rlh;
829 rlh = (struct RecordLookupHandle*) cls;
830
831 if (strcmp(rh->name, "") == 0)
832 {
833 /* We resolved full name for delegation. resolving record */
834 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
835 "Resolved full name for delegation. resolving record ''\n");
836 rh->proc = &handle_record_ns;
837 resolve_record_ns(rh);
838 return;
839 }
840
841 /**
842 * we still have some left
843 * check if ns entry is fresh
844 **/
845 if (rh->status & (EXISTS | !EXPIRED))
846 {
847 if (is_canonical(rh->name))
848 {
849 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
850 "Resolving canonical record %s\n", rh->name);
851 rh->proc = &handle_record_ns;
852 resolve_record_ns(rh);
853 }
854 else
855 {
856 /* give up, cannot resolve */
857 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
858 "Cannot fully resolve delegation for %s!\n",
859 rh->name);
860 rlh->proc(rlh->proc_cls, 0, NULL);
861 }
862 return;
863 }
864
865 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
866 "Trying to resolve delegation for %s via DHT\n",
867 rh->name);
868 rh->proc = &handle_delegation_dht;
869 resolve_delegation_dht(rh);
870}
871
872//Prototype
873static void resolve_delegation_ns(struct ResolverHandle *rh);
874
875
876/**
877 * This is a callback function that should give us only PKEY
878 * records. Used to query the namestore for the authority (PKEY)
879 * for 'name'. It will recursively try to resolve the
880 * authority for a given name from the namestore.
881 *
882 * @param cls the pending query
883 * @param key the key of the zone we did the lookup
884 * @param expiration expiration date of the record data set in the namestore
885 * @param name the name for which we need an authority
886 * @param rd_count the number of records with 'name'
887 * @param rd the record data
888 * @param signature the signature of the authority for the record data
889 */
890static void
891process_delegation_result_ns(void* cls,
892 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
893 struct GNUNET_TIME_Absolute expiration,
894 const char *name,
895 unsigned int rd_count,
896 const struct GNUNET_NAMESTORE_RecordData *rd,
897 const struct GNUNET_CRYPTO_RsaSignature *signature)
898{
899 struct ResolverHandle *rh;
900 struct GNUNET_TIME_Relative remaining_time;
901 GNUNET_HashCode zone;
902 char* new_name;
903
904 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
905 rd_count);
906
907 rh = (struct ResolverHandle *)cls;
908 GNUNET_CRYPTO_hash(key,
909 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
910 &zone);
911 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
912
913 rh->status = 0;
914
915 if (name != NULL)
916 {
917 rh->status |= EXISTS;
918 }
919
920 if (remaining_time.rel_value == 0)
921 {
922 rh->status |= EXPIRED;
923 }
924
925 /**
926 * No authority found in namestore.
927 */
928 if (rd_count == 0)
929 {
930 /**
931 * We did not find an authority in the namestore
932 */
933
934 /**
935 * No PKEY in zone.
936 * Promote this authority back to a name maybe it is
937 * our record.
938 */
939 if (strcmp(rh->name, "") == 0)
940 {
941 /* simply promote back */
942 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
943 "Promoting %s back to name\n", rh->authority_name);
944 strcpy(rh->name, rh->authority_name);
945 }
946 else
947 {
948 /* add back to existing name */
949 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
950 "Adding %s back to %s\n",
951 rh->authority_name, rh->name);
952 new_name = GNUNET_malloc(strlen(rh->name)
953 + strlen(rh->authority_name) + 2);
954 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
955 strcpy(new_name, rh->name);
956 strcpy(new_name+strlen(new_name)+1, ".");
957 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
958 GNUNET_free(rh->name);
959 rh->name = new_name;
960 }
961 rh->proc(rh->proc_cls, rh, 0, NULL);
962 return;
963 }
964
965 //Note only 1 pkey should have been returned.. anything else would be strange
966 /**
967 * We found an authority that may be able to help us
968 * move on with query
969 */
970 int i;
971 for (i=0; i<rd_count;i++)
972 {
973
974 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
975 continue;
976
977 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
978 == 0)
979 {
980 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
981 if (remaining_time.rel_value == 0)
982 {
983 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
984 "This dht entry is expired.\n");
985 rh->authority_chain_head->fresh = 0;
986 rh->proc(rh->proc_cls, rh, 0, NULL);
987 return;
988 }
989
990 continue;
991 }
992
993 /**
994 * Resolve rest of query with new authority
995 */
996 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
997 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
998 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
999 auth->zone = rh->authority;
1000 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1001 memset(auth->name, 0, strlen(rh->authority_name)+1);
1002 strcpy(auth->name, rh->authority_name);
1003 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1004 rh->authority_chain_tail,
1005 auth);
1006
1007 /**
1008 * We are done with PKEY resolution if name is empty
1009 * else resolve again with new authority
1010 */
1011 if (strcmp(rh->name, "") == 0)
1012 rh->proc(rh->proc_cls, rh, 0, NULL);
1013 else
1014 resolve_delegation_ns(rh);
1015 return;
1016 }
1017
1018 /**
1019 * no answers found
1020 */
1021 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1022 "Authority lookup successful but no PKEY... never get here\n");
1023 rh->proc(rh->proc_cls, rh, 0, NULL);
1024}
1025
1026
1027/**
1028 * Resolve the delegation chain for the request in our namestore
1029 *
1030 * @param rh the resolver handle
1031 */
1032static void
1033resolve_delegation_ns(struct ResolverHandle *rh)
1034{
1035 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1036 "Resolving delegation for %s\n", rh->name);
1037 pop_tld(rh->name, rh->authority_name);
1038 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1039 &rh->authority,
1040 rh->authority_name,
1041 GNUNET_GNS_RECORD_PKEY,
1042 &process_delegation_result_ns,
1043 rh);
1044
1045}
1046
1047
1048/**
1049 * Lookup of a record in a specific zone
1050 * calls lookup result processor on result
1051 *
1052 * @param zone the root zone
1053 * @param record_type the record type to look up
1054 * @param proc the processor to call
1055 * @param cls the closure to pass to proc
1056 */
1057void
1058gns_resolver_lookup_record(GNUNET_HashCode zone,
1059 uint32_t record_type,
1060 const char* name,
1061 RecordLookupProcessor proc,
1062 void* cls)
1063{
1064 struct ResolverHandle *rh;
1065 struct RecordLookupHandle* rlh;
1066
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Starting resolution for %s (type=%d)!\n",
1069 name, record_type);
1070
1071 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1072 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1073
1074 rh->authority = zone;
1075 rh->proc_cls = rlh;
1076 rh->name = GNUNET_malloc(strlen(name)
1077 - strlen(GNUNET_GNS_TLD));
1078 memset(rh->name, 0,
1079 strlen(name)-strlen(GNUNET_GNS_TLD));
1080 memcpy(rh->name, name,
1081 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1082 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1083 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1084 rh->authority_chain_head->prev = NULL;
1085 rh->authority_chain_head->next = NULL;
1086 rh->authority_chain_tail = rh->authority_chain_head;
1087 rh->authority_chain_head->zone = zone;
1088
1089 rlh->record_type = record_type;
1090 rlh->name = (char*)name; //FIXME
1091 rlh->proc = proc;
1092 rlh->proc_cls = cls;
1093
1094 rh->proc = &handle_delegation_ns;
1095 resolve_delegation_ns(rh);
1096}
1097
1098/******** END Record Resolver ***********/
1099
1100
1101static void
1102process_pseu_result_ns_shorten(void *cls,
1103 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1104 struct GNUNET_TIME_Absolute expire,
1105 const char *name,
1106 unsigned int rd_len,
1107 const struct GNUNET_NAMESTORE_RecordData *rd,
1108 const struct GNUNET_CRYPTO_RsaSignature *signature)
1109{
1110 struct ResolverHandle *rh =
1111 (struct ResolverHandle *)cls;
1112 struct GNUNET_TIME_Relative remaining_time;
1113
1114 GNUNET_TIME_absolute_get_remaining (expire);
1115 rh->status = 0;
1116
1117 if (name != NULL)
1118 {
1119 rh->status |= EXISTS;
1120 }
1121
1122 if (remaining_time.rel_value == 0)
1123 {
1124 rh->status |= EXPIRED;
1125 }
1126
1127 rh->proc(rh->proc_cls, rh, rd_len, rd);
1128}
1129
1130
1131/**
1132 * Function called when we get a result from the dht
1133 * for our record query
1134 *
1135 * @param cls the request handle
1136 * @param exp lifetime
1137 * @param key the key the record was stored under
1138 * @param get_path get path
1139 * @param get_path_length get path length
1140 * @param put_path put path
1141 * @param put_path_length put path length
1142 * @param type the block type
1143 * @param size the size of the record
1144 * @param data the record data
1145 */
1146static void
1147process_pseu_dht_result(void* cls,
1148 struct GNUNET_TIME_Absolute exp,
1149 const GNUNET_HashCode * key,
1150 const struct GNUNET_PeerIdentity *get_path,
1151 unsigned int get_path_length,
1152 const struct GNUNET_PeerIdentity *put_path,
1153 unsigned int put_path_length,
1154 enum GNUNET_BLOCK_Type type,
1155 size_t size, const void *data)
1156{
1157 struct ResolverHandle *rh;
1158 struct RecordLookupHandle *rlh;
1159 struct GNSNameRecordBlock *nrb;
1160 uint32_t num_records;
1161 char* name = NULL;
1162 char* rd_data = (char*)data;
1163 int i;
1164 int rd_size;
1165
1166 GNUNET_HashCode zone, name_hash;
1167 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got PSEU dht result (size=%d)\n", size);
1168
1169 if (data == NULL)
1170 return;
1171
1172 //FIXME maybe check expiration here, check block type
1173
1174 rh = (struct ResolverHandle *)cls;
1175 rlh = (struct RecordLookupHandle *) rh->proc_cls;
1176 nrb = (struct GNSNameRecordBlock*)data;
1177
1178 /* stop lookup and timeout task */
1179 GNUNET_DHT_get_stop (rh->get_handle);
1180 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
1181
1182 rh->get_handle = NULL;
1183 name = (char*)&nrb[1];
1184 num_records = ntohl(nrb->rd_count);
1185 {
1186 struct GNUNET_NAMESTORE_RecordData rd[num_records];
1187
1188 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1189 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1190
1191 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1192 rd_data,
1193 num_records,
1194 rd))
1195 {
1196 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
1197 return;
1198 }
1199
1200 for (i=0; i<num_records; i++)
1201 {
1202 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1203 "Got name: %s (wanted %s)\n", name, rh->name);
1204 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1205 "Got type: %d\n",
1206 rd[i].record_type);
1207 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1208 "Got data length: %d\n", rd[i].data_size);
1209 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1210 "Got flag %d\n", rd[i].flags);
1211
1212 if ((strcmp(name, "+") == 0) &&
1213 (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
1214 {
1215 rh->answered++;
1216 }
1217
1218 }
1219
1220 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1221 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
1222
1223 /**
1224 * FIXME check pubkey against existing key in namestore?
1225 * https://gnunet.org/bugs/view.php?id=2179
1226 */
1227
1228 /* Save to namestore */
1229 GNUNET_NAMESTORE_record_put (namestore_handle,
1230 &nrb->public_key,
1231 name,
1232 exp,
1233 num_records,
1234 rd,
1235 &nrb->signature,
1236 &on_namestore_record_put_result, //cont
1237 NULL); //cls
1238
1239 if (rh->answered)
1240 rh->proc(rh->proc_cls, rh, num_records, rd);
1241 else
1242 rh->proc(rh->proc_cls, rh, 0, NULL);
1243 }
1244
1245}
1246
1247
1248/**
1249 * Start DHT lookup for a PSEUdonym record in
1250 * rh->authority's zone
1251 *
1252 * @param rh the pending gns query
1253 */
1254static void
1255resolve_pseu_dht(struct ResolverHandle *rh)
1256{
1257 uint32_t xquery;
1258 GNUNET_HashCode name_hash;
1259 GNUNET_HashCode lookup_key;
1260
1261 GNUNET_CRYPTO_hash("+",
1262 strlen("+"),
1263 &name_hash);
1264
1265 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1266
1267 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1268 &dht_lookup_timeout,
1269 rh);
1270
1271 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
1272
1273 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1274 DHT_OPERATION_TIMEOUT,
1275 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1276 &lookup_key,
1277 DHT_GNS_REPLICATION_LEVEL,
1278 GNUNET_DHT_RO_NONE,
1279 &xquery,
1280 sizeof(xquery),
1281 &process_pseu_dht_result,
1282 rh);
1283
1284}
1285
1286//Prototype
1287static void
1288handle_shorten_pseu_ns_result(void* cls,
1289 struct ResolverHandle *rh,
1290 uint32_t rd_count,
1291 const struct GNUNET_NAMESTORE_RecordData *rd);
1292
1293static void
1294process_zone_to_name_shorten(void *cls,
1295 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1296 struct GNUNET_TIME_Absolute expire,
1297 const char *name,
1298 unsigned int rd_len,
1299 const struct GNUNET_NAMESTORE_RecordData *rd,
1300 const struct GNUNET_CRYPTO_RsaSignature *signature)
1301{
1302 struct ResolverHandle *rh =
1303 (struct ResolverHandle *)cls;
1304 struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1305 struct AuthorityChain *next_authority;
1306
1307 char* result;
1308 char* next_authority_name;
1309 size_t answer_len;
1310
1311 /* we found a match in our own zone */
1312 if (rd_len != 0)
1313 {
1314 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1315 "result strlen %d\n", strlen(name));
1316 answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1317 result = GNUNET_malloc(answer_len);
1318 memset(result, 0, answer_len);
1319 strcpy(result, rh->name);
1320 strcpy(result+strlen(rh->name), ".");
1321 strcpy(result+strlen(rh->name)+1, name);
1322 strcpy(result+strlen(rh->name)+strlen(name)+1, ".");
1323 strcpy(result+strlen(rh->name)+strlen(name)+2, GNUNET_GNS_TLD);
1324
1325 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1326 "Sending shorten result %s\n", result);
1327
1328 nsh->proc(nsh->proc_cls, result);
1329 free_resolver_handle(rh);
1330 GNUNET_free(result);
1331 }
1332 else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1333 &rh->authority_chain_tail->zone))
1334 {
1335 /* our zone, just append .gnunet */
1336 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1337 result = GNUNET_malloc(answer_len);
1338 memset(result, 0, answer_len);
1339 strcpy(result, rh->name);
1340 strcpy(result+strlen(rh->name), ".");
1341 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1342
1343 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1344 "Our zone: Sending name as shorten result %s\n", rh->name);
1345
1346 nsh->proc(nsh->proc_cls, result); //FIXME +.gnunet!
1347 free_resolver_handle(rh);
1348 GNUNET_free(result);
1349 }
1350 else
1351 {
1352 /**
1353 * No PSEU found.
1354 * continue with next authority
1355 */
1356 next_authority = rh->authority_chain_head;
1357 next_authority_name = GNUNET_malloc(strlen(rh->name)+
1358 strlen(next_authority->name) + 2);
1359 memset(next_authority_name, 0, strlen(rh->name)+
1360 strlen(next_authority->name) + 2);
1361 strcpy(next_authority_name, rh->name);
1362 strcpy(next_authority_name+strlen(rh->name)+1, ".");
1363 strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1364
1365 GNUNET_free(rh->name);
1366 rh->name = next_authority_name;
1367 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1368 rh->authority_chain_tail,
1369 next_authority);
1370
1371 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1372 &rh->authority_chain_tail->zone,
1373 &rh->authority_chain_head->zone,
1374 &process_zone_to_name_shorten,
1375 rh);
1376 }
1377}
1378
1379
1380/**
1381 * Process result from namestore PSEU lookup
1382 * for shorten operation
1383 *
1384 * @param cls the client shorten handle
1385 * @param rh the resolver handle
1386 * @param rd_count number of results (0 if none found)
1387 * @param rd data (NULL if none found)
1388 */
1389static void
1390handle_pseu_ns_result_shorten(void* cls,
1391 struct ResolverHandle *rh,
1392 uint32_t rd_len,
1393 const struct GNUNET_NAMESTORE_RecordData *rd)
1394{
1395 struct NameShortenHandle* nsh = (struct NameShortenHandle*) cls;
1396 struct AuthorityChain *next_authority;
1397 char* pseu;
1398 char* result;
1399 char* new_name;
1400 size_t answer_len;
1401 int i;
1402
1403 /**
1404 * PSEU found
1405 */
1406 if (rd_len != 0)
1407 {
1408 for (i=0; i < rd_len; i++)
1409 {
1410 if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1411 {
1412 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1413 "Found PSEU %s len %d\n", (char*) rd[i].data,
1414 strlen((char*) rd[i].data));
1415 break;
1416 }
1417 }
1418
1419 pseu = (char*) rd[i].data;
1420 answer_len = strlen(rh->name) + strlen(pseu) + strlen(GNUNET_GNS_TLD) + 3;
1421 result = GNUNET_malloc(answer_len);
1422 memset(result, 0, answer_len);
1423 strcpy(result, rh->name);
1424 strcpy(result+strlen(rh->name), ".");
1425 strcpy(result+strlen(rh->name)+1, pseu);
1426 strcpy(result+strlen(rh->name)+strlen(pseu)+1, ".");
1427 strcpy(result+strlen(rh->name)+strlen(pseu)+2, GNUNET_GNS_TLD);
1428
1429 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1430 "Sending shorten result %s\n", result);
1431
1432 nsh->proc(nsh->proc_cls, result);
1433 free_resolver_handle(rh);
1434 GNUNET_free(result);
1435 return;
1436 }
1437
1438 /**
1439 * No PSEU found.
1440 * continue with next authority
1441 * Note that we never have <2 authorities
1442 * in our list at this point since tail is always our root
1443 * And we filter fot this in handle_delegation_ns_shorten
1444 */
1445 next_authority = rh->authority_chain_head;
1446 new_name = GNUNET_malloc(strlen(rh->name)+
1447 strlen(next_authority->name) + 2);
1448 memset(new_name, 0, strlen(rh->name)+
1449 strlen(next_authority->name) + 2);
1450 strcpy(new_name, rh->name);
1451 strcpy(new_name+strlen(rh->name)+1, ".");
1452 strcpy(new_name+strlen(rh->name)+2, next_authority->name);
1453
1454 GNUNET_free(rh->name);
1455 rh->name = new_name;
1456 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1457 rh->authority_chain_tail,
1458 next_authority);
1459
1460 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1461 &rh->authority_chain_tail->zone,
1462 &rh->authority_chain_head->zone,
1463 &process_zone_to_name_shorten,
1464 rh);
1465
1466}
1467
1468
1469
1470/**
1471 * Process result from namestore delegation lookup
1472 * for shorten operation
1473 *
1474 * @param cls the client shorten handle
1475 * @param rh the resolver handle
1476 * @param rd_count number of results (0)
1477 * @param rd data (NULL)
1478 */
1479void
1480handle_delegation_ns_shorten(void* cls,
1481 struct ResolverHandle *rh,
1482 uint32_t rd_count,
1483 const struct GNUNET_NAMESTORE_RecordData *rd)
1484{
1485 struct NameShortenHandle *nsh;
1486 char* result;
1487 size_t answer_len;
1488
1489 nsh = (struct NameShortenHandle *)cls;
1490
1491 /**
1492 * At this point rh->name contains the part of the name
1493 * that we do not have a PKEY in our namestore to resolve.
1494 * The authority chain in the resolver handle is now
1495 * useful to backtrack if needed
1496 */
1497
1498 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1499 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1500
1501 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1502 &rh->authority_chain_tail->zone) == 0)
1503 {
1504 /**
1505 * This is our zone append .gnunet unless name is empty
1506 * (it shouldn't be, usually FIXME what happens if we
1507 * shorten to our zone to a "" record??)
1508 **/
1509
1510 answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1511 result = GNUNET_malloc(answer_len);
1512 memset(result, 0, answer_len);
1513 strcpy(result, rh->name);
1514 strcpy(result+strlen(rh->name), ".");
1515 strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1516
1517 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1518 "Our zone: Sending name as shorten result %s\n", rh->name);
1519
1520 nsh->proc(nsh->proc_cls, result); //FIXME +.gnunet!
1521 free_resolver_handle(rh);
1522 GNUNET_free(result);
1523 return;
1524 }
1525
1526 /* backtrack authorities for names */
1527 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1528 &rh->authority_chain_tail->zone, //ours
1529 &rh->authority_chain_head->zone,
1530 &process_zone_to_name_shorten,
1531 rh);
1532
1533}
1534
1535/**
1536 * Shorten api from resolver
1537 *
1538 * @param zone the zone to use
1539 * @param name the name to shorten
1540 * @param proc the processor to call with result
1541 * @param cls closure to pass to proc
1542 */
1543void
1544gns_resolver_shorten_name(GNUNET_HashCode zone,
1545 const char* name,
1546 ShortenResultProcessor proc,
1547 void* cls)
1548{
1549 struct ResolverHandle *rh;
1550 struct NameShortenHandle *nsh;
1551
1552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1553 "Starting shorten for %s!\n", name);
1554
1555 nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1556 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1557 rh->authority = zone;
1558 rh->name = GNUNET_malloc(strlen(name)
1559 - strlen(GNUNET_GNS_TLD));
1560 memset(rh->name, 0,
1561 strlen(name)-strlen(GNUNET_GNS_TLD));
1562 memcpy(rh->name, name,
1563 strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1564
1565 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1566 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1567 rh->authority_chain_tail = rh->authority_chain_head;
1568 rh->authority_chain_head->zone = zone;
1569 rh->proc = &handle_delegation_ns_shorten;
1570 rh->proc_cls = nsh;
1571
1572 nsh->proc = proc;
1573 nsh->proc_cls = cls;
1574
1575 /* Start delegation resolution in our namestore */
1576 resolve_delegation_ns(rh);
1577}
1578
1579/*********** END NAME SHORTEN ********************/
1580
1581
1582/**
1583 * Process result from namestore delegation lookup
1584 * for get authority operation
1585 *
1586 * @param cls the client get auth handle
1587 * @param rh the resolver handle
1588 * @param rd_count number of results (0)
1589 * @param rd data (NULL)
1590 */
1591void
1592handle_delegation_result_ns_get_auth(void* cls,
1593 struct ResolverHandle *rh,
1594 uint32_t rd_count,
1595 const struct GNUNET_NAMESTORE_RecordData *rd)
1596{
1597 struct GetNameAuthorityHandle* nah;
1598 char* result;
1599 size_t answer_len;
1600
1601 nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1602
1603 /**
1604 * At this point rh->name contains the part of the name
1605 * that we do not have a PKEY in our namestore to resolve.
1606 * The authority chain in the resolver handle is now
1607 * useful to backtrack if needed
1608 */
1609
1610 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1611 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1612
1613 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1614 "Building response!\n");
1615 if (is_canonical(rh->name))
1616 {
1617 /**
1618 * We successfully resolved the authority in the ns
1619 * FIXME for our purposes this is fine
1620 * but maybe we want to have an api that also looks
1621 * into the dht (i.e. option in message)
1622 **/
1623 if (strlen(rh->name) > strlen(nah->name))
1624 {
1625 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1626 "Record name longer than original lookup name... odd!\n");
1627 //FIXME to sth here
1628 }
1629
1630 answer_len = strlen(nah->name) - strlen(rh->name)
1631 + strlen(GNUNET_GNS_TLD) + 1;
1632 result = GNUNET_malloc(answer_len);
1633 memset(result, 0, answer_len);
1634 strcpy(result, nah->name + strlen(rh->name) + 1);
1635
1636 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1637 "Got authority result %s\n", result);
1638
1639 nah->proc(nah->proc_cls, result);
1640 free_resolver_handle(rh);
1641 GNUNET_free(result);
1642 GNUNET_free(nah);
1643 }
1644 else
1645 {
1646 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1647 "Unable to resolve authority for remaining %s!\n", rh->name);
1648 nah->proc(nah->proc_cls, "");
1649 free_resolver_handle(rh);
1650 GNUNET_free(nah);
1651 }
1652
1653
1654}
1655
1656
1657/**
1658 * Tries to resolve the authority for name
1659 * in our namestore
1660 *
1661 * @param zone the root zone to look up for
1662 * @param name the name to lookup up
1663 * @param proc the processor to call when finished
1664 * @param cls the closure to pass to the processor
1665 */
1666void
1667gns_resolver_get_authority(GNUNET_HashCode zone,
1668 const char* name,
1669 GetAuthorityResultProcessor proc,
1670 void* cls)
1671{
1672 struct ResolverHandle *rh;
1673 struct GetNameAuthorityHandle *nah;
1674
1675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1676 "Starting authority resolution for %s!\n", name);
1677
1678 nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1679 rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1680 rh->authority = zone;
1681
1682 rh->name = GNUNET_malloc(strlen(name)
1683 - strlen(GNUNET_GNS_TLD));
1684 memset(rh->name, 0,
1685 strlen(name)-strlen(GNUNET_GNS_TLD));
1686 memcpy(rh->name, name,
1687 strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1688
1689 nah->name = GNUNET_malloc(strlen(name)+1);
1690 memset(nah->name, 0,
1691 strlen(name)+1);
1692 strcpy(nah->name, name);
1693
1694 rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1695
1696 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1697 rh->authority_chain_tail = rh->authority_chain_head;
1698 rh->authority_chain_head->zone = zone;
1699 rh->proc = &handle_delegation_result_ns_get_auth;
1700 rh->proc_cls = (void*)nah;
1701
1702 nah->proc = proc;
1703 nah->proc_cls = cls;
1704
1705 /* Start delegation resolution in our namestore */
1706 resolve_delegation_ns(rh);
1707
1708}
1709
1710/******** END GET AUTHORITY *************/
1711
1712/* end of gns_resolver.c */
diff --git a/src/gns/gnunet-service-gns_resolver.h b/src/gns/gnunet-service-gns_resolver.h
new file mode 100644
index 000000000..2b0c4755d
--- /dev/null
+++ b/src/gns/gnunet-service-gns_resolver.h
@@ -0,0 +1,226 @@
1#ifndef GNS_RESOLVER_H
2#define GNS_RESOLVER_H
3
4#include "gns.h"
5
6#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
7#define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
8#define DHT_GNS_REPLICATION_LEVEL 5
9#define MAX_DNS_LABEL_LENGTH 63
10
11/*
12 * DLL to hold the authority chain
13 * we had to pass in the resolution process
14 */
15struct AuthorityChain
16{
17 struct AuthorityChain *prev;
18
19 struct AuthorityChain *next;
20
21 /* the zone hash of the authority */
22 GNUNET_HashCode zone;
23
24 /* (local) name of the authority */
25 char* name;
26
27 /* was the ns entry fresh */
28 int fresh;
29};
30
31/* handle to a resolution process */
32struct ResolverHandle;
33
34/**
35 * processor for a resultion result
36 *
37 * @param cls the closure
38 * @param rh the resolution handle
39 * @param rd_count number of results
40 * @pram rd resukt data
41 */
42typedef void (*RecordLookupProcessor) (void *cls,
43 uint32_t rd_count,
44 const struct GNUNET_NAMESTORE_RecordData *rd);
45
46
47/**
48 * processor for a shorten result
49 *
50 * @param cls the closure
51 * @param name shortened name
52 */
53typedef void (*ShortenResultProcessor) (void *cls, const char* name);
54
55
56/**
57 * processor for an authority result
58 *
59 * @param cls the closure
60 * @param name name
61 */
62typedef void (*GetAuthorityResultProcessor) (void *cls, const char* name);
63
64/**
65 * processor for a resultion result
66 *
67 * @param cls the closure
68 * @param rh the resolution handle
69 * @param rd_count number of results
70 * @param rd result data
71 */
72typedef void (*ResolutionResultProcessor) (void *cls,
73 struct ResolverHandle *rh,
74 uint32_t rd_count,
75 const struct GNUNET_NAMESTORE_RecordData *rd);
76
77
78/**
79 * Resoltion status indicator
80 * EXISTS: the name to lookup exists
81 * EXPIRED: the name in the record expired
82 */
83enum ResolutionStatus
84{
85 EXISTS = 1,
86 EXPIRED = 2
87};
88
89/**
90 * Handle to a currenty pending resolution
91 */
92struct ResolverHandle
93{
94 /* The name to resolve */
95 char *name;
96
97 /* has this query been answered? how many matches */
98 int answered;
99
100 /* the authoritative zone to query */
101 GNUNET_HashCode authority;
102
103 /* the name of the authoritative zone to query */
104 char *authority_name;
105
106 /**
107 * we have an authority in namestore that
108 * may be able to resolve
109 */
110 int authority_found;
111
112 /* a handle for dht lookups. should be NULL if no lookups are in progress */
113 struct GNUNET_DHT_GetHandle *get_handle;
114
115 /* timeout task for dht lookups */
116 GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
117
118 /* called when resolution phase finishes */
119 ResolutionResultProcessor proc;
120
121 /* closure passed to proc */
122 void* proc_cls;
123
124 /* DLL to store the authority chain */
125 struct AuthorityChain *authority_chain_head;
126
127 /* DLL to store the authority chain */
128 struct AuthorityChain *authority_chain_tail;
129
130 /* status of the resolution result */
131 enum ResolutionStatus status;
132
133};
134
135
136/**
137 * Handle to a record lookup
138 */
139struct RecordLookupHandle
140{
141 /* the record type to look up */
142 enum GNUNET_GNS_RecordType record_type;
143
144 /* the name to look up */
145 char *name;
146
147 /* Method to call on record resolution result */
148 RecordLookupProcessor proc;
149
150 /* closure to pass to proc */
151 void* proc_cls;
152
153};
154
155
156/**
157 * Handle to a shorten context
158 */
159struct NameShortenHandle
160{
161
162
163 /* Method to call on shorten result */
164 ShortenResultProcessor proc;
165
166 /* closure to pass to proc */
167 void* proc_cls;
168
169};
170
171/**
172 * Handle to a get authority context
173 */
174struct GetNameAuthorityHandle
175{
176
177 /* the name to look up authority for */
178 char* name;
179
180 /* Method to call on result */
181 GetAuthorityResultProcessor proc;
182
183 /* closure to pass to proc */
184 void* proc_cls;
185
186};
187
188
189/**
190 * Lookup of a record in a specific zone
191 * calls lookup result processor on result
192 *
193 * @param zone the root zone
194 * @param record_type the record type to look up
195 * @param proc the processor to call
196 * @param cls the closure to pass to proc
197 */
198void
199gns_resolver_lookup_record(GNUNET_HashCode zone,
200 uint32_t record_type,
201 const char* name,
202 RecordLookupProcessor proc,
203 void* cls);
204
205void
206gns_resolver_shorten_name(GNUNET_HashCode zone,
207 const char* name,
208 ShortenResultProcessor proc,
209 void* cls);
210
211/**
212 * Tries to resolve the authority for name
213 * in our namestore
214 *
215 * @param zone the root zone to look up for
216 * @param name the name to lookup up
217 * @param proc the processor to call when finished
218 * @param cls the closure to pass to the processor
219 */
220void
221gns_resolver_get_authority(GNUNET_HashCode zone,
222 const char* name,
223 GetAuthorityResultProcessor proc,
224 void* cls);
225
226#endif
diff --git a/src/gns/test_gns_dht_shorten.c b/src/gns/test_gns_dht_shorten.c
deleted file mode 100644
index 32d978290..000000000
--- a/src/gns/test_gns_dht_shorten.c
+++ /dev/null
@@ -1,500 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
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.
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 General Public License for more details.
14
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.
19*/
20/**
21 * @file gns/test_gns_twopeer.c
22 * @brief base testcase for testing DHT service with
23 * two running peers.
24 *
25 * This testcase starts peers using the GNUNET_TESTING_daemons_start
26 * function call. On peer start, connects to the peers DHT service
27 * by calling GNUNET_DHT_connected. Once notified about all peers
28 * being started (by the peers_started_callback function), calls
29 * GNUNET_TESTING_connect_topology, which connects the peers in a
30 * "straight line" topology. On notification that all peers have
31 * been properly connected, calls the do_get function which initiates
32 * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get
33 * function starts, runs the do_put function to insert data at the first peer.
34 * If the GET is successful, schedules finish_testing
35 * to stop the test and shut down peers. If GET is unsuccessful
36 * after GET_TIMEOUT seconds, prints an error message and shuts down
37 * the peers.
38 */
39#include "platform.h"
40#include "gnunet_testing_lib.h"
41#include "gnunet_core_service.h"
42#include "block_gns.h"
43#include "gnunet_signatures.h"
44#include "gnunet_namestore_service.h"
45#include "../namestore/namestore.h"
46#include "gnunet_dnsparser_lib.h"
47#include "gnunet_dht_service.h"
48#include "gnunet_gns_service.h"
49
50/* DEFINES */
51#define VERBOSE GNUNET_YES
52
53/* Timeout for entire testcase */
54#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
55
56/* If number of peers not in config file, use this number */
57#define DEFAULT_NUM_PEERS 2
58
59/* test records to resolve */
60#define TEST_DOMAIN "www.alice.bob.gnunet"
61#define TEST_IP "127.0.0.1"
62#define TEST_RECORD_NAME "www"
63
64#define TEST_AUTHORITY_NAME "bob"
65#define TEST_AUTHORITY_ALICE "alice"
66#define TEST_ALICE_PSEU "carol"
67#define TEST_EXPECTED_RESULT "www.carol.gnunet"
68
69#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
70
71/* Globals */
72
73/**
74 * Directory to store temp data in, defined in config file
75 */
76static char *test_directory;
77
78struct GNUNET_TESTING_Daemon *d1;
79
80
81/* Task handle to use to schedule test failure */
82GNUNET_SCHEDULER_TaskIdentifier die_task;
83
84/* Global return value (0 for success, anything else for failure) */
85static int ok;
86
87static struct GNUNET_NAMESTORE_Handle *namestore_handle;
88
89static struct GNUNET_GNS_Handle *gns_handle;
90
91static struct GNUNET_DHT_Handle *dht_handle;
92
93const struct GNUNET_CONFIGURATION_Handle *cfg;
94
95struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey;
96struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey;
97struct GNUNET_CRYPTO_RsaPrivateKey *alice_key;
98struct GNUNET_CRYPTO_RsaPrivateKey *bob_key;
99
100/**
101 * Check whether peers successfully shut down.
102 */
103void
104shutdown_callback (void *cls, const char *emsg)
105{
106 if (emsg != NULL)
107 {
108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok);
109 if (ok == 0)
110 ok = 2;
111 }
112
113 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok);
114}
115
116
117/**
118 * Called when gns shorten finishes
119 */
120static void
121process_shorten_result(void* cls, const char* sname)
122{
123 GNUNET_GNS_disconnect(gns_handle);
124
125 ok = 0;
126
127 if (sname == NULL)
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130 "shorten test failed!\n");
131 ok = 1;
132 }
133 else
134 {
135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
136 "%s shortened to %s\n", (char*)cls, sname);
137 if (0 != strcmp(sname, TEST_EXPECTED_RESULT))
138 {
139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
140 "shorten test failed! (wanted: %s got: %s\n",
141 (char*)cls, sname);
142 ok = 1;
143 }
144
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shorten test succeeded!\n");
146
147 }
148
149 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n");
150 GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL,
151 GNUNET_YES, GNUNET_NO);
152}
153
154/**
155 * Function scheduled to be run on the successful start of services
156 * tries to look up the dns record for TEST_DOMAIN
157 */
158static void
159commence_testing (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
160{
161 GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES);
162
163 gns_handle = GNUNET_GNS_connect(cfg);
164
165 if (NULL == gns_handle)
166 {
167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
168 "Failed to connect to GNS!\n");
169 ok = 1;
170 }
171
172 GNUNET_GNS_shorten(gns_handle, TEST_DOMAIN, &process_shorten_result,
173 TEST_DOMAIN);
174}
175
176/**
177 * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut
178 * down the peers without freeing memory associated with GET request.
179 */
180static void
181end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
182{
183
184 if (d1 != NULL)
185 GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL,
186 GNUNET_YES, GNUNET_NO);
187 GNUNET_SCHEDULER_cancel (die_task);
188}
189
190/**
191 * Check if the get_handle is being used, if so stop the request. Either
192 * way, schedule the end_badly_cont function which actually shuts down the
193 * test.
194 */
195static void
196end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
197{
198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n",
199 (char *) cls);
200 GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL);
201 ok = 1;
202}
203
204
205static void
206put_www_dht(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
207{
208 struct GNSNameRecordBlock *nrb;
209 GNUNET_HashCode name_hash;
210 GNUNET_HashCode xor_hash;
211 GNUNET_HashCode zone_hash;
212 uint32_t rd_payload_length;
213 char* nrb_data = NULL;
214 struct GNUNET_CRYPTO_RsaSignature *sig;
215 struct GNUNET_NAMESTORE_RecordData rd;
216 char* ip = TEST_IP;
217 struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr));
218
219 rd.expiration = GNUNET_TIME_absolute_get_forever ();
220 GNUNET_assert(1 == inet_pton (AF_INET, ip, web));
221 rd.data_size = sizeof(struct in_addr);
222 rd.data = web;
223 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
224
225 sig = GNUNET_NAMESTORE_create_signature(alice_key,
226 GNUNET_TIME_absolute_get_forever(),
227 TEST_RECORD_NAME,
228 &rd, 1);
229 rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd);
230 nrb = GNUNET_malloc(rd_payload_length + strlen(TEST_RECORD_NAME) + 1
231 + sizeof(struct GNSNameRecordBlock));
232 nrb->signature = *sig;
233 nrb->public_key = alice_pkey;
234 nrb->rd_count = htonl(1);
235 memset(&nrb[1], 0, strlen(TEST_RECORD_NAME) + 1);
236 memcpy(&nrb[1], TEST_RECORD_NAME, strlen(TEST_RECORD_NAME));
237 nrb_data = (char*)&nrb[1];
238 nrb_data += strlen(TEST_RECORD_NAME) + 1;
239
240 if (-1 == GNUNET_NAMESTORE_records_serialize (1,
241 &rd,
242 rd_payload_length,
243 nrb_data))
244 {
245 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
246 ok = 3;
247 GNUNET_free (nrb);
248 return;
249 }
250 GNUNET_CRYPTO_hash(TEST_RECORD_NAME, strlen(TEST_RECORD_NAME), &name_hash);
251 GNUNET_CRYPTO_hash(&alice_pkey,
252 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
253 &zone_hash);
254 GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
255
256 rd_payload_length += sizeof(struct GNSNameRecordBlock) +
257 strlen(TEST_RECORD_NAME) + 1;
258 GNUNET_DHT_put (dht_handle, &xor_hash,
259 0,
260 GNUNET_DHT_RO_NONE,
261 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
262 rd_payload_length,
263 (char*)nrb,
264 rd.expiration,
265 DHT_OPERATION_TIMEOUT,
266 NULL,
267 NULL);
268 GNUNET_free (nrb);
269 GNUNET_SCHEDULER_add_delayed(TIMEOUT, &commence_testing, NULL);
270}
271
272
273static void
274put_alice_pseu_dht(void *cls, int32_t success, const char *emsg)
275{
276 struct GNSNameRecordBlock *nrb;
277 GNUNET_HashCode name_hash;
278 GNUNET_HashCode xor_hash;
279 GNUNET_HashCode zone_hash;
280 uint32_t rd_payload_length;
281 char* nrb_data = NULL;
282 struct GNUNET_CRYPTO_RsaSignature *sig;
283 struct GNUNET_NAMESTORE_RecordData rd;
284
285 rd.expiration = GNUNET_TIME_absolute_get_forever ();
286 rd.data_size = strlen(TEST_ALICE_PSEU);
287 rd.data = TEST_ALICE_PSEU;
288 rd.record_type = GNUNET_GNS_RECORD_PSEU;
289
290 sig = GNUNET_NAMESTORE_create_signature(alice_key,
291 GNUNET_TIME_absolute_get_forever(),
292 "+", //empty name for pseu
293 &rd, 1);
294 rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd);
295 nrb = GNUNET_malloc(rd_payload_length + strlen("") + 1
296 + sizeof(struct GNSNameRecordBlock));
297 nrb->signature = *sig;
298 nrb->public_key = alice_pkey;
299 nrb->rd_count = htonl(1);
300 memset(&nrb[1], 0, strlen("+") + 1);
301 memcpy(&nrb[1], "+", strlen("+"));
302 nrb_data = (char*)&nrb[1];
303 nrb_data += strlen("+") + 1;
304
305 if (-1 == GNUNET_NAMESTORE_records_serialize (1,
306 &rd,
307 rd_payload_length,
308 nrb_data))
309 {
310 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
311 ok = 3;
312 GNUNET_free (nrb);
313 return;
314 }
315 GNUNET_CRYPTO_hash("+", strlen("+"), &name_hash);
316 GNUNET_CRYPTO_hash(&alice_pkey,
317 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
318 &zone_hash);
319 GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
320
321 rd_payload_length += sizeof(struct GNSNameRecordBlock) +
322 strlen("+") + 1;
323 GNUNET_DHT_put (dht_handle, &xor_hash,
324 0,
325 GNUNET_DHT_RO_NONE,
326 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
327 rd_payload_length,
328 (char*)nrb,
329 rd.expiration,
330 DHT_OPERATION_TIMEOUT,
331 NULL,
332 NULL);
333 GNUNET_free (nrb);
334 GNUNET_SCHEDULER_add_delayed(TIMEOUT, &put_www_dht, NULL);
335}
336
337static void
338do_shorten(void *cls, const struct GNUNET_PeerIdentity *id,
339 const struct GNUNET_CONFIGURATION_Handle *cfg,
340 struct GNUNET_TESTING_Daemon *d, const char *emsg)
341{
342
343 char* my_keyfile;
344 struct GNUNET_CRYPTO_RsaPrivateKey *my_key;
345 GNUNET_HashCode bob_hash;
346 GNUNET_HashCode alice_hash;
347 struct GNUNET_CRYPTO_RsaSignature *sig;
348
349
350 GNUNET_SCHEDULER_cancel (die_task);
351
352 /* put records into namestore */
353 namestore_handle = GNUNET_NAMESTORE_connect(cfg);
354 if (NULL == namestore_handle)
355 {
356 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n");
357 ok = -1;
358 return;
359 }
360
361 /* dht */
362 dht_handle = GNUNET_DHT_connect(cfg, 1);
363 if (NULL == dht_handle)
364 {
365 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to dht\n");
366 ok = -1;
367 return;
368 }
369
370 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns",
371 "ZONEKEY",
372 &my_keyfile))
373 {
374 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
375 ok = -1;
376 return;
377 }
378
379 my_key = GNUNET_CRYPTO_rsa_key_create_from_file (my_keyfile);
380 alice_key = GNUNET_CRYPTO_rsa_key_create ();
381 bob_key = GNUNET_CRYPTO_rsa_key_create ();
382
383 GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey);
384 GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey);
385 GNUNET_CRYPTO_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash);
386 GNUNET_CRYPTO_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash);
387
388 struct GNUNET_NAMESTORE_RecordData rd;
389 rd.expiration = GNUNET_TIME_absolute_get_forever ();
390 rd.data_size = sizeof(GNUNET_HashCode);
391 rd.data = &bob_hash;
392 rd.record_type = GNUNET_GNS_RECORD_PKEY;
393
394 GNUNET_NAMESTORE_record_create (namestore_handle,
395 my_key,
396 TEST_AUTHORITY_NAME,
397 &rd,
398 NULL,
399 NULL);
400
401 rd.data = &alice_hash;
402
403 sig = GNUNET_NAMESTORE_create_signature(bob_key,
404 GNUNET_TIME_absolute_get_forever(),
405 TEST_AUTHORITY_ALICE,
406 &rd,
407 1);
408
409 GNUNET_NAMESTORE_record_put (namestore_handle,
410 &bob_pkey,
411 TEST_AUTHORITY_ALICE,
412 GNUNET_TIME_absolute_get_forever(),
413 1,
414 &rd,
415 sig,
416 &put_alice_pseu_dht,
417 NULL);
418
419
420
421
422
423}
424
425static void
426run (void *cls, char *const *args, const char *cfgfile,
427 const struct GNUNET_CONFIGURATION_Handle *c)
428{
429 cfg = c;
430 /* Get path from configuration file */
431 if (GNUNET_YES !=
432 GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome",
433 &test_directory))
434 {
435 ok = 404;
436 return;
437 }
438
439
440 /* Set up a task to end testing if peer start fails */
441 die_task =
442 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly,
443 "didn't start all daemons in reasonable amount of time!!!");
444
445 /* Start alice */
446 d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0,
447 NULL, NULL, NULL, &do_shorten, NULL);
448}
449
450static int
451check ()
452{
453 int ret;
454
455 /* Arguments for GNUNET_PROGRAM_run */
456 char *const argv[] = { "test-gns-dht-delegated-lookup", /* Name to give running binary */
457 "-c",
458 "test_gns_simple_lookup.conf", /* Config file to use */
459#if VERBOSE
460 "-L", "DEBUG",
461#endif
462 NULL
463 };
464 struct GNUNET_GETOPT_CommandLineOption options[] = {
465 GNUNET_GETOPT_OPTION_END
466 };
467 /* Run the run function as a new program */
468 ret =
469 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
470 "test-gns-dht-delegated-lookup", "nohelp", options, &run,
471 &ok);
472 if (ret != GNUNET_OK)
473 {
474 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
475 "`test-gns-dht-delegated-lookup': Failed with error code %d\n", ret);
476 }
477 return ok;
478}
479
480int
481main (int argc, char *argv[])
482{
483 int ret;
484
485 GNUNET_log_setup ("test-gns-simple-lookup",
486#if VERBOSE
487 "DEBUG",
488#else
489 "WARNING",
490#endif
491 NULL);
492 ret = check ();
493 /**
494 * Need to remove base directory, subdirectories taken care
495 * of by the testing framework.
496 */
497 return ret;
498}
499
500/* end of test_gns_twopeer.c */
diff --git a/src/gns/test_gns_simple_shorten.c b/src/gns/test_gns_simple_shorten.c
index 17076bb4a..8f93c471f 100644
--- a/src/gns/test_gns_simple_shorten.c
+++ b/src/gns/test_gns_simple_shorten.c
@@ -285,25 +285,18 @@ do_shorten(void *cls, const struct GNUNET_PeerIdentity *id,
285 NULL, 285 NULL,
286 NULL); 286 NULL);
287 287
288 rd.data_size = strlen(TEST_ALICE_PSEU); 288 rd.data_size = sizeof(GNUNET_HashCode);
289 rd.data = TEST_ALICE_PSEU; 289 rd.data = &alice_hash;
290 rd.record_type = GNUNET_GNS_RECORD_PSEU; 290 rd.record_type = GNUNET_GNS_RECORD_PKEY;
291 GNUNET_free(sig); 291 GNUNET_free(sig);
292 292
293 sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_absolute_get_forever(), "+", 293 GNUNET_NAMESTORE_record_create (namestore_handle,
294 &rd, 1); 294 our_key,
295 295 TEST_ALICE_PSEU,
296 GNUNET_NAMESTORE_record_put (namestore_handle,
297 &alice_pkey,
298 "+",
299 GNUNET_TIME_absolute_get_forever(),
300 1,
301 &rd, 296 &rd,
302 sig,
303 &commence_testing, 297 &commence_testing,
304 NULL); 298 NULL);
305 299
306 GNUNET_free(sig);
307 300
308} 301}
309 302