From: Martin Schanzenbach Date: Sun, 4 Mar 2012 23:09:12 +0000 (+0000) Subject: -rewritten resolver, hits some namestore bugs X-Git-Tag: initial-import-from-subversion-38251~14443 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=f6e67ed3bb4cec5645b7cb81c44c34a115294051;p=oweals%2Fgnunet.git -rewritten resolver, hits some namestore bugs --- diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c index 934ebd2c1..8222e459f 100644 --- a/src/gns/gnunet-service-gns.c +++ b/src/gns/gnunet-service-gns.c @@ -42,6 +42,7 @@ #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT #define DHT_GNS_REPLICATION_LEVEL 5 +#define MAX_DNS_LABEL_LENGTH 63 /* Ignore for now not used anyway and probably never will */ #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23 @@ -142,12 +143,112 @@ static int num_public_records = 3600; struct GNUNET_TIME_Relative dht_update_interval; GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; -/* Prototypes */ -static void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, - uint32_t rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd); static void resolve_name(struct GNUNET_GNS_ResolverHandle *rh); +/** + * Reply to client with the result from our lookup. + * + * @param rh the request handle of the lookup + * @param rd_count the number of records to return + * @param rd the record data + */ +static void +reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + int i; + size_t len; + int ret; + char *buf; + struct GNUNET_DNSPARSER_Packet *packet = rh->packet; + struct GNUNET_DNSPARSER_Record answer_records[rh->answered]; + struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)]; + packet->answers = answer_records; + packet->additional_records = additional_records; + + /** + * Put records in the DNS packet and modify it + * to a response + */ + len = sizeof(struct GNUNET_DNSPARSER_Record*); + for (i=0; i < rd_count; i++) + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Adding type %d to DNS response\n", rd[i].record_type); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size); + + if (rd[i].record_type == rh->query->type) + { + answer_records[i].name = rh->query->name; + answer_records[i].type = rd[i].record_type; + answer_records[i].data.raw.data_len = rd[i].data_size; + answer_records[i].data.raw.data = (char*)rd[i].data; + answer_records[i].expiration_time = rd[i].expiration; + answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn + } + else + { + additional_records[i].name = rh->query->name; + additional_records[i].type = rd[i].record_type; + additional_records[i].data.raw.data_len = rd[i].data_size; + additional_records[i].data.raw.data = (char*)rd[i].data; + additional_records[i].expiration_time = rd[i].expiration; + additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn + } + } + + packet->num_answers = rh->answered; + packet->num_additional_records = rd_count-(rh->answered); + + if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) + packet->flags.authoritative_answer = 1; + else + packet->flags.authoritative_answer = 0; + + if (rd == NULL) + packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR; + else + packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; + + packet->flags.query_or_response = 1; + + + /** + * Reply to DNS + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Building DNS response\n"); + ret = GNUNET_DNSPARSER_pack (packet, + 1024, /* FIXME magic from dns redirector */ + &buf, + &len); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Built DNS response! (ret=%d,len=%d)\n", ret, len); + if (ret == GNUNET_OK) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Answering DNS request\n"); + GNUNET_DNS_request_answer(rh->request_handle, + len, + buf); + //GNUNET_free(answer); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n"); + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Error building DNS response! (ret=%d)", ret); + } + + GNUNET_free(rh->name); + GNUNET_free(rh); +} + + /** * Task run during shutdown. * @@ -229,7 +330,7 @@ dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param data the record data */ static void -process_authority_dht_result(void* cls, +process_record_dht_result(void* cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, @@ -243,29 +344,31 @@ process_authority_dht_result(void* cls, struct GNSNameRecordBlock *nrb; uint32_t num_records; char* name = NULL; - char* rd_data = (char*) data; + char* rd_data = (char*)data; int i; int rd_size; + GNUNET_HashCode zone, name_hash; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size); if (data == NULL) return; - - //FIXME check expiration? + + //FIXME maybe check expiration here, check block type rh = (struct GNUNET_GNS_ResolverHandle *)cls; nrb = (struct GNSNameRecordBlock*)data; - /* stop dht lookup and timeout task */ + /* stop lookup and timeout task */ GNUNET_DHT_get_stop (rh->get_handle); GNUNET_SCHEDULER_cancel(rh->dht_timeout_task); - + rh->get_handle = NULL; - num_records = ntohl(nrb->rd_count); name = (char*)&nrb[1]; + num_records = ntohl(nrb->rd_count); { struct GNUNET_NAMESTORE_RecordData rd[num_records]; - + rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); @@ -278,42 +381,36 @@ process_authority_dht_result(void* cls, return; } - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got name: %s (wanted %s)\n", name, rh->authority_name); for (i=0; iauthority_name); + "Got name: %s (wanted %s)\n", name, rh->name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got type: %d (wanted %d)\n", - rd[i].record_type, GNUNET_GNS_RECORD_PKEY); + "Got type: %d (wanted %d)\n", + rd[i].record_type, rh->query->type); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got data length: %d\n", rd[i].data_size); + "Got data length: %d\n", rd[i].data_size); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got flag %d\n", rd[i].flags); - - if ((strcmp(name, rh->authority_name) == 0) && - (rd[i].record_type == GNUNET_GNS_RECORD_PKEY)) + "Got flag %d\n", rd[i].flags); + + if ((strcmp(name, rh->name) == 0) && + (rd[i].record_type == rh->query->type)) { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n"); - rh->answered = 1; - GNUNET_CRYPTO_hash( - (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *)rd[i].data, - rd[i].data_size, - &rh->authority); + rh->answered++; } } - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone); + + /** + * FIXME check pubkey against existing key in namestore? + * https://gnunet.org/bugs/view.php?id=2179 + */ /* Save to namestore */ - if (0 == GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone)) - { - GNUNET_NAMESTORE_record_put (namestore_handle, + GNUNET_NAMESTORE_record_put (namestore_handle, &nrb->public_key, name, exp, @@ -322,56 +419,184 @@ process_authority_dht_result(void* cls, &nrb->signature, &on_namestore_record_put_result, //cont NULL); //cls - } - } - if (rh->answered) - { - rh->answered = 0; - resolve_name(rh); - return; + if (rh->answered) + reply_to_dns(rh, num_records, rd); + else + reply_to_dns(rh, 0, NULL); } - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n"); - reply_to_dns(rh, 0, NULL); + } + /** - * Start DHT lookup for a name -> PKEY (compare NS) record in + * Start DHT lookup for a (name -> query->record_type) record in * query->authority's zone * - * @param rh the pending gns query - * @param name the name of the PKEY record + * @param rh the pending gns query context + * @param name the name to query record */ static void -resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh) +resolve_record_dht(struct GNUNET_GNS_ResolverHandle *rh) { uint32_t xquery; GNUNET_HashCode name_hash; GNUNET_HashCode lookup_key; + struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; - GNUNET_CRYPTO_hash(rh->authority_name, - strlen(rh->authority_name), - &name_hash); + GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash); GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key); + GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "starting dht lookup for %s with key: %s\n", + rh->name, (char*)&lookup_key_string); - rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT, - &dht_lookup_timeout, rh); + rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT, + &dht_lookup_timeout, rh); - xquery = htonl(GNUNET_GNS_RECORD_PKEY); - //FIXME how long to wait for results? - rh->get_handle = GNUNET_DHT_get_start(dht_handle, + xquery = htonl(rh->query->type); + rh->get_handle = GNUNET_DHT_get_start(dht_handle, DHT_OPERATION_TIMEOUT, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, &lookup_key, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, - &xquery, + &xquery, sizeof(xquery), - &process_authority_dht_result, + &process_record_dht_result, rh); } + +/** + * Namestore calls this function if we have record for this name. + * (or with rd_count=0 to indicate no matches) + * + * @param cls the pending query + * @param key the key of the zone we did the lookup + * @param expiration expiration date of the namestore entry + * @param name the name for which we need an authority + * @param rd_count the number of records with 'name' + * @param rd the record data + * @param signature the signature of the authority for the record data + */ +static void +process_record_lookup(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct GNUNET_GNS_ResolverHandle *rh; + struct GNUNET_TIME_Relative remaining_time; + GNUNET_HashCode zone; + + rh = (struct GNUNET_GNS_ResolverHandle *) cls; + GNUNET_CRYPTO_hash(key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone); + remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); + + if (rd_count == 0) + { + /** + * Lookup terminated and no results + * -> DHT Phase unless data is recent + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Namestore lookup for %s terminated without results\n", name); + + /** + * Not our root and no record found. Try dht if expired + */ + if ((0 != GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) && + (remaining_time.rel_value != 0)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Record %s unknown in namestore, trying dht\n", + rh->name); + resolve_record_dht(rh); + return; + } + + /** + * Our zone and no result? Cannot resolve TT + */ + GNUNET_assert(rh->answered == 0); + reply_to_dns(rh, 0, NULL); + return; + + } + else + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Processing additional result %s from namestore\n", name); + int i; + for (i=0; iquery->type) + continue; + + if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value + == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n"); + continue; + } + + rh->answered++; + + } + + /** + * no answers found + */ + if (rh->answered == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "No answers found. This is odd!\n"); + reply_to_dns(rh, 0, NULL); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n", + rh->answered); + + reply_to_dns(rh, rd_count, rd); + } +} + + +/** + * The final phase of resolution. + * This is a name that is canonical and we do not have a delegation. + * + * @param rh the pending lookup + */ +static void +resolve_record(struct GNUNET_GNS_ResolverHandle *rh) +{ + + /** + * Try to resolve this record in our namestore. + * The name to resolve is now in rh->authority_name + * since we tried to resolve it to an authority + * and failed. + **/ + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &rh->authority, + rh->name, + rh->query->type, + &process_record_lookup, + rh); + +} + /** * Function called when we get a result from the dht * for our query @@ -388,7 +613,7 @@ resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh) * @param data the record data */ static void -process_name_dht_result(void* cls, +process_authority_dht_result(void* cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, @@ -402,31 +627,29 @@ process_name_dht_result(void* cls, struct GNSNameRecordBlock *nrb; uint32_t num_records; char* name = NULL; - char* rd_data = (char*)data; + char* rd_data = (char*) data; int i; int rd_size; - GNUNET_HashCode zone, name_hash; - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size); if (data == NULL) return; - - //FIXME maybe check expiration here, check block type + + //FIXME check expiration? rh = (struct GNUNET_GNS_ResolverHandle *)cls; nrb = (struct GNSNameRecordBlock*)data; - /* stop lookup and timeout task */ + /* stop dht lookup and timeout task */ GNUNET_DHT_get_stop (rh->get_handle); GNUNET_SCHEDULER_cancel(rh->dht_timeout_task); - + rh->get_handle = NULL; - name = (char*)&nrb[1]; num_records = ntohl(nrb->rd_count); + name = (char*)&nrb[1]; { struct GNUNET_NAMESTORE_RecordData rd[num_records]; - + rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); @@ -439,36 +662,42 @@ process_name_dht_result(void* cls, return; } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got name: %s (wanted %s)\n", name, rh->authority_name); for (i=0; iname); + "Got name: %s (wanted %s)\n", name, rh->authority_name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got type: %d (wanted %d)\n", - rd[i].record_type, rh->query->type); + "Got type: %d (wanted %d)\n", + rd[i].record_type, GNUNET_GNS_RECORD_PKEY); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got data length: %d\n", rd[i].data_size); + "Got data length: %d\n", rd[i].data_size); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got flag %d\n", rd[i].flags); - - if ((strcmp(name, rh->name) == 0) && - (rd[i].record_type == rh->query->type)) + "Got flag %d\n", rd[i].flags); + + if ((strcmp(name, rh->authority_name) == 0) && + (rd[i].record_type == GNUNET_GNS_RECORD_PKEY)) { - rh->answered++; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n"); + rh->answered = 1; + GNUNET_CRYPTO_hash( + (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *)rd[i].data, + rd[i].data_size, + &rh->authority); } } + GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone); - - /** - * FIXME check pubkey against existing key in namestore? - * https://gnunet.org/bugs/view.php?id=2179 - */ /* Save to namestore */ - GNUNET_NAMESTORE_record_put (namestore_handle, + if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone)) + { + GNUNET_NAMESTORE_record_put (namestore_handle, &nrb->public_key, name, exp, @@ -477,66 +706,70 @@ process_name_dht_result(void* cls, &nrb->signature, &on_namestore_record_put_result, //cont NULL); //cls + } + } - if (rh->answered) - reply_to_dns(rh, num_records, rd); + if (rh->answered) + { + rh->answered = 0; + /* delegate */ + if (strcmp(rh->name, "") == 0) + resolve_record(rh); else - reply_to_dns(rh, 0, NULL); + resolve_name(rh); + return; } + /* resolve */ + if (strcmp(rh->name, "") == 0) + { + /* promote authority back to name */ + strcpy(rh->name, rh->authority_name); + resolve_record(rh); + return; + } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n"); + reply_to_dns(rh, 0, NULL); } - - - /** - * Start DHT lookup for a (name -> query->record_type) record in + * Start DHT lookup for a name -> PKEY (compare NS) record in * query->authority's zone * - * @param rh the pending gns query context - * @param name the name to query record + * @param rh the pending gns query + * @param name the name of the PKEY record */ static void -resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name) +resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh) { uint32_t xquery; GNUNET_HashCode name_hash; GNUNET_HashCode lookup_key; - struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "A\n"); - - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_hash(rh->authority_name, + strlen(rh->authority_name), + &name_hash); GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key); - GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "starting dht lookup for %s with key: %s\n", - name, (char*)&lookup_key_string); - rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT, - &dht_lookup_timeout, rh); + rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT, + &dht_lookup_timeout, + rh); - xquery = htonl(rh->query->type); + xquery = htonl(GNUNET_GNS_RECORD_PKEY); //FIXME how long to wait for results? - rh->get_handle = GNUNET_DHT_get_start(dht_handle, + rh->get_handle = GNUNET_DHT_get_start(dht_handle, DHT_OPERATION_TIMEOUT, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, &lookup_key, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, - &xquery, - sizeof(xquery), - &process_name_dht_result, + NULL, + 0,//sizeof(xquery), + &process_authority_dht_result, rh); } -//Prototype -static void -resolve_name(struct GNUNET_GNS_ResolverHandle *rh); - /** * This is a callback function that should give us only PKEY * records. Used to query the namestore for the authority (PKEY) @@ -582,8 +815,38 @@ process_authority_lookup(void* cls, * _IF_ the current authoritative zone is us we cannot resolve * _ELSE_ we can still check the _expired_ dht */ - if ((0 != GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) && - (remaining_time.rel_value == 0)) + + /** + * No PKEY in our root. Try to resolve actual type in our zone + * if name is canonical. Else we cannot resolve. + */ + if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) + { + if (strcmp(rh->name, "") == 0) + { + /** + * Promote this authority back to a name + */ + strcpy(rh->name, rh->authority_name); + resolve_record(rh); + return; + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Authority %s unknown in namestore, cannot resolve\n", + rh->authority_name); + } + reply_to_dns(rh, 0, NULL); + return; + } + + /** + * Not our root and no PKEY found. Try dht if expired + * FIXME only do when expired? + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "AAAA %d\n", remaining_time.rel_value); + if ((0 != GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority %s unknown in namestore, trying dht\n", @@ -591,6 +854,10 @@ process_authority_lookup(void* cls, resolve_authority_dht(rh); return; } + + /** + * Not our root and not expired or no records. Cannot resolve + */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority %s unknown\n", rh->authority_name); reply_to_dns(rh, 0, NULL); @@ -618,6 +885,7 @@ process_authority_lookup(void* cls, GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This dht entry is expired. Refreshing\n"); resolve_authority_dht(rh); + return; } continue; @@ -630,7 +898,10 @@ process_authority_lookup(void* cls, GNUNET_CRYPTO_hash(rd[i].data, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &rh->authority); - resolve_name(rh); + if (strcmp(rh->name, "") == 0) + resolve_record(rh); + else + resolve_name(rh); return; } @@ -643,220 +914,6 @@ process_authority_lookup(void* cls, } -/** - * Reply to client with the result from our lookup. - * - * @param rh the request handle of the lookup - * @param rd_count the number of records to return - * @param rd the record data - */ -static void -reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd) -{ - int i; - size_t len; - int ret; - char *buf; - struct GNUNET_DNSPARSER_Packet *packet = rh->packet; - struct GNUNET_DNSPARSER_Record answer_records[rh->answered]; - struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)]; - packet->answers = answer_records; - packet->additional_records = additional_records; - - /** - * Put records in the DNS packet and modify it - * to a response - */ - len = sizeof(struct GNUNET_DNSPARSER_Record*); - for (i=0; i < rd_count; i++) - { - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Adding type %d to DNS response\n", rd[i].record_type); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size); - - if (rd[i].record_type == rh->query->type) - { - answer_records[i].name = rh->query->name; - answer_records[i].type = rd[i].record_type; - answer_records[i].data.raw.data_len = rd[i].data_size; - answer_records[i].data.raw.data = (char*)rd[i].data; - answer_records[i].expiration_time = rd[i].expiration; - answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn - } - else - { - additional_records[i].name = rh->query->name; - additional_records[i].type = rd[i].record_type; - additional_records[i].data.raw.data_len = rd[i].data_size; - additional_records[i].data.raw.data = (char*)rd[i].data; - additional_records[i].expiration_time = rd[i].expiration; - additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn - } - } - - packet->num_answers = rh->answered; - packet->num_additional_records = rd_count-(rh->answered); - - if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) - packet->flags.authoritative_answer = 1; - else - packet->flags.authoritative_answer = 0; - - if (rd == NULL) - packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR; - else - packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; - - packet->flags.query_or_response = 1; - - - /** - * Reply to DNS - */ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Building DNS response\n"); - ret = GNUNET_DNSPARSER_pack (packet, - 1024, /* FIXME magic from dns redirector */ - &buf, - &len); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Built DNS response! (ret=%d,len=%d)\n", ret, len); - if (ret == GNUNET_OK) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Answering DNS request\n"); - GNUNET_DNS_request_answer(rh->request_handle, - len, - buf); - //GNUNET_free(answer); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n"); - } - else - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, - "Error building DNS response! (ret=%d)", ret); - } - - GNUNET_free(rh->name); - GNUNET_free(rh); -} - - -/** - * Namestore calls this function if we have record for this name. - * (or with rd_count=0 to indicate no matches) - * - * @param cls the pending query - * @param key the key of the zone we did the lookup - * @param expiration expiration date of the namestore entry - * @param name the name for which we need an authority - * @param rd_count the number of records with 'name' - * @param rd the record data - * @param signature the signature of the authority for the record data - */ -static void -process_authoritative_result(void* cls, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, - struct GNUNET_TIME_Absolute expiration, - const char *name, unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) -{ - struct GNUNET_GNS_ResolverHandle *rh; - struct GNUNET_TIME_Relative remaining_time; - GNUNET_HashCode zone; - - rh = (struct GNUNET_GNS_ResolverHandle *) cls; - GNUNET_CRYPTO_hash(key, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &zone); - remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); - - if (rd_count == 0) - { - /** - * Lookup terminated and no results - * -> DHT Phase unless data is recent - */ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Namestore lookup for %s terminated without results\n", name); - - /** - * if this is not our zone we cannot rely on the namestore to be - * complete. -> Query DHT - */ - if (GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash)) - { - if (remaining_time.rel_value == 0) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "trying dht...\n"); - resolve_name_dht(rh, rh->name); - return; - } - else - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Record is still recent. No DHT lookup\n"); - } - } - - /** - * Our zone and no result? Cannot resolve TT - */ - GNUNET_assert(rh->answered == 0); - reply_to_dns(rh, 0, NULL); - return; - - } - else - { - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Processing additional result %s from namestore\n", name); - int i; - for (i=0; iquery->name) == 0) - && (rd[i].record_type != rh->query->type)) - continue; - - if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value - == 0) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n"); - continue; - } - - rh->answered++; - - } - - /** - * no answers found - * consult dht if expired - */ - if ((remaining_time.rel_value == 0) && (rh->answered == 0)) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "This dht entry is old. Refreshing.\n"); - resolve_name_dht(rh, name); - return; - } - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n", - rh->answered); - - reply_to_dns(rh, rd_count, rd); - } -} - /** * Determine if this name is canonical. * i.e. @@ -885,28 +942,33 @@ is_canonical(char* name) * passed top level domain. * * @param name the domain - * @return the tld + * @param dest the destination where the tld will be put */ -static char* -pop_tld(char* name) +void +pop_tld(char* name, char* dest) { uint32_t len; if (is_canonical(name)) - return NULL; + { + strcpy(dest, name); + strcpy(name, ""); + return; + } for (len = strlen(name); len > 0; len--) { if (*(name+len) == '.') break; } - + + //Was canonical? if (len == 0) - return NULL; + return; name[len] = '\0'; - return (name+len+1); + strcpy(dest, (name+len+1)); } @@ -921,27 +983,18 @@ pop_tld(char* name) static void resolve_name(struct GNUNET_GNS_ResolverHandle *rh) { - if (is_canonical(rh->name)) - { - /* We only need to check the current zone's ns */ - GNUNET_NAMESTORE_lookup_record(namestore_handle, - &rh->authority, - rh->name, - rh->query->type, - &process_authoritative_result, - rh); - } - else - { - /* We have to resolve the authoritative entity first */ - rh->authority_name = pop_tld(rh->name); - GNUNET_NAMESTORE_lookup_record(namestore_handle, + + /** + * Try to resolve this name to a delegation. + **/ + pop_tld(rh->name, rh->authority_name); + GNUNET_NAMESTORE_lookup_record(namestore_handle, &rh->authority, rh->authority_name, GNUNET_GNS_RECORD_PKEY, &process_authority_lookup, rh); - } + } /** @@ -975,6 +1028,8 @@ start_resolution(struct GNUNET_DNS_RequestHandle *request, memcpy(rh->name, q->name, strlen(q->name)-strlen(gnunet_tld)); + rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH); + rh->request_handle = request; /* Start resolution in our zone */