aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gnunet-service-gns_resolver.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-08-14 17:28:42 +0000
committerChristian Grothoff <christian@grothoff.org>2013-08-14 17:28:42 +0000
commit8576071c0bd953da120d10df71d64bdccb4aefc8 (patch)
tree1f4e81bb4d2735b6efa3cf28ef052b8049427d3e /src/gns/gnunet-service-gns_resolver.c
parent3717f40062d8163854a9b1df3a698bca86d27b69 (diff)
downloadgnunet-8576071c0bd953da120d10df71d64bdccb4aefc8.tar.gz
gnunet-8576071c0bd953da120d10df71d64bdccb4aefc8.zip
-more work on clean main GNS logic
Diffstat (limited to 'src/gns/gnunet-service-gns_resolver.c')
-rw-r--r--src/gns/gnunet-service-gns_resolver.c933
1 files changed, 784 insertions, 149 deletions
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
index de9e7e014..1519d4223 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -47,10 +47,20 @@
47#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) 47#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
48 48
49/** 49/**
50 * Default timeout for DNS lookups.
51 */
52#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
53
54/**
50 * DHT replication level 55 * DHT replication level
51 */ 56 */
52#define DHT_GNS_REPLICATION_LEVEL 5 57#define DHT_GNS_REPLICATION_LEVEL 5
53 58
59/**
60 * How deep do we allow recursions to go before we abort?
61 */
62#define MAX_RECURSION 256
63
54 64
55/** 65/**
56 * DLL to hold the authority chain we had to pass in the resolution 66 * DLL to hold the authority chain we had to pass in the resolution
@@ -69,9 +79,14 @@ struct AuthorityChain
69 struct AuthorityChain *next; 79 struct AuthorityChain *next;
70 80
71 /** 81 /**
72 * label corresponding to the authority 82 * Resolver handle this entry in the chain belongs to.
73 */ 83 */
74 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH]; 84 struct GNS_ResolverHandle *rh;
85
86 /**
87 * label/name corresponding to the authority
88 */
89 char *label;
75 90
76 /** 91 /**
77 * #GNUNET_YES if the authority was a GNS authority, 92 * #GNUNET_YES if the authority was a GNS authority,
@@ -161,6 +176,46 @@ enum ResolutionStatus
161 176
162 177
163/** 178/**
179 * A result we got from DNS.
180 */
181struct DnsResult
182{
183
184 /**
185 * Kept in DLL.
186 */
187 struct DnsResult *next;
188
189 /**
190 * Kept in DLL.
191 */
192 struct DnsResult *prev;
193
194 /**
195 * Binary value stored in the DNS record (appended to this struct)
196 */
197 const void *data;
198
199 /**
200 * Expiration time for the DNS record, 0 if we didn't
201 * get anything useful (i.e. 'gethostbyname' was used).
202 */
203 uint64_t expiration_time;
204
205 /**
206 * Number of bytes in 'data'.
207 */
208 size_t data_size;
209
210 /**
211 * Type of the GNS/DNS record.
212 */
213 uint32_t record_type;
214
215};
216
217
218/**
164 * Handle to a currenty pending resolution. On result (positive or 219 * Handle to a currenty pending resolution. On result (positive or
165 * negative) the #GNS_ResultProcessor is called. 220 * negative) the #GNS_ResultProcessor is called.
166 */ 221 */
@@ -208,9 +263,14 @@ struct GNS_ResolverHandle
208 struct GNUNET_DNSSTUB_RequestSocket *dns_request; 263 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
209 264
210 /** 265 /**
266 * Handle for standard DNS resolution, NULL if none is active.
267 */
268 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
269
270 /**
211 * Pending Namestore task 271 * Pending Namestore task
212 */ 272 */
213 struct GNUNET_NAMESTORE_QueueEntry *namestore_task; 273 struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
214 274
215 /** 275 /**
216 * Heap node associated with this lookup. Used to limit number of 276 * Heap node associated with this lookup. Used to limit number of
@@ -221,12 +281,12 @@ struct GNS_ResolverHandle
221 /** 281 /**
222 * DLL to store the authority chain 282 * DLL to store the authority chain
223 */ 283 */
224 struct AuthorityChain *authority_chain_head; 284 struct AuthorityChain *ac_head;
225 285
226 /** 286 /**
227 * DLL to store the authority chain 287 * DLL to store the authority chain
228 */ 288 */
229 struct AuthorityChain *authority_chain_tail; 289 struct AuthorityChain *ac_tail;
230 290
231 /** 291 /**
232 * Private key of the shorten zone, NULL to not shorten. 292 * Private key of the shorten zone, NULL to not shorten.
@@ -234,9 +294,24 @@ struct GNS_ResolverHandle
234 struct GNUNET_CRYPTO_EccPrivateKey *shorten_key; 294 struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
235 295
236 /** 296 /**
297 * ID of a task associated with the resolution process.
298 */
299 GNUNET_SCHEDULER_TaskIdentifier task_id;
300
301 /**
237 * The name to resolve 302 * The name to resolve
238 */ 303 */
239 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH]; 304 char *name;
305
306 /**
307 * DLL of results we got from DNS.
308 */
309 struct DnsResult *dns_result_head;
310
311 /**
312 * DLL of results we got from DNS.
313 */
314 struct DnsResult *dns_result_tail;
240 315
241 /** 316 /**
242 * Current offset in 'name' where we are resolving. 317 * Current offset in 'name' where we are resolving.
@@ -248,6 +323,18 @@ struct GNS_ResolverHandle
248 */ 323 */
249 int only_cached; 324 int only_cached;
250 325
326 /**
327 * Desired type for the resolution.
328 */
329 int record_type;
330
331 /**
332 * We increment the loop limiter for each step in a recursive
333 * resolution. If it passes our threshold (i.e. due to
334 * self-recursion in the resolution, i.e CNAME fun), we stop.
335 */
336 unsigned int loop_limiter;
337
251}; 338};
252 339
253 340
@@ -326,7 +413,7 @@ static struct GNUNET_DNSSTUB_Context *dns_handle;
326static struct GNUNET_CONTAINER_Heap *dht_lookup_heap; 413static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
327 414
328/** 415/**
329 * Maximum amount of parallel queries in background 416 * Maximum amount of parallel queries to the DHT
330 */ 417 */
331static unsigned long long max_allowed_background_queries; 418static unsigned long long max_allowed_background_queries;
332 419
@@ -2884,6 +2971,546 @@ resolve_delegation_ns (struct ResolverHandle *rh)
2884 2971
2885#endif 2972#endif
2886 2973
2974///////////////////////////////////////////////////////////////////////////////////////////////////
2975///////////////////////////////////////////////////////////////////////////////////////////////////
2976///////////////////////////////////////////////////////////////////////////////////////////////////
2977///////////////////////////////////////////////////////////////////////////////////////////////////
2978///////////////////////////////////////////////////////////////////////////////////////////////////
2979
2980
2981/**
2982 * Task scheduled to asynchronously fail a resolution.
2983 *
2984 * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
2985 * @param tc task context
2986 */
2987static void
2988fail_resolution (void *cls,
2989 const struct GNUNET_SCHEDULER_TaskContext *tc)
2990{
2991 struct GNS_ResolverHandle *rh = cls;
2992
2993 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
2994 rh->proc (rh->proc_cls, 0, NULL);
2995 GNS_resolver_lookup_cancel (rh);
2996}
2997
2998
2999/**
3000 * Get the next, rightmost label from the name that we are trying to resolve,
3001 * and update the resolution position accordingly.
3002 *
3003 * @param rh handle to the resolution operation to get the next label from
3004 * @return NULL if there are no more labels
3005 */
3006static char *
3007resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
3008{
3009 const char *rp;
3010 const char *dot;
3011 size_t len;
3012
3013 if (0 == rh->name_resolution_pos)
3014 return NULL;
3015 dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
3016 if (NULL == dot)
3017 {
3018 /* done, this was the last one */
3019 len = rh->name_resolution_pos;
3020 rp = rh->name;
3021 rh->name_resolution_pos = 0;
3022 }
3023 else
3024 {
3025 /* advance by one label */
3026 len = rh->name_resolution_pos - (dot - rh->name) - 1;
3027 rp = dot + 1;
3028 rh->name_resolution_pos = dot - rh->name;
3029 }
3030 return GNUNET_strndup (rp, len);
3031}
3032
3033
3034/**
3035 * Gives the cummulative result obtained to the callback and clean up the request.
3036 *
3037 * @param rh resolution process that has culminated in a result
3038 */
3039static void
3040transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
3041{
3042 struct DnsResult *pos;
3043 unsigned int n;
3044 unsigned int i;
3045
3046 n = 0;
3047 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
3048 n++;
3049 {
3050 struct GNUNET_NAMESTORE_RecordData rd[n];
3051
3052 i = 0;
3053 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
3054 {
3055 rd[i].data = pos->data;
3056 rd[i].data_size = pos->data_size;
3057 rd[i].record_type = pos->record_type;
3058 if (0 == pos->expiration_time)
3059 {
3060 rd[i].flags = GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
3061 rd[i].expiration_time = 0;
3062 }
3063 else
3064 {
3065 rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
3066 rd[i].expiration_time = pos->expiration_time;
3067 }
3068 }
3069 rh->proc (rh->proc_cls,
3070 n,
3071 rd);
3072 }
3073 GNS_resolver_lookup_cancel (rh);
3074}
3075
3076
3077/**
3078 * Add a result from DNS to the records to be returned to the application.
3079 *
3080 * @param rh resolution request to extend with a result
3081 * @param expiration_time expiration time for the answer
3082 * @param record_type DNS record type of the answer
3083 * @param data_size number of bytes in @a data
3084 * @param data binary data to return in DNS record
3085 */
3086static void
3087add_dns_result (struct GNS_ResolverHandle *rh,
3088 uint64_t expiration_time,
3089 uint32_t record_type,
3090 size_t data_size,
3091 const void *data)
3092{
3093 struct DnsResult *res;
3094
3095 res = GNUNET_malloc (sizeof (struct DnsResult) + data_size);
3096 res->expiration_time = expiration_time;
3097 res->data_size = data_size;
3098 res->record_type = record_type;
3099 res->data = &res[1];
3100 memcpy (&res[1], data, data_size);
3101 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
3102 rh->dns_result_tail,
3103 res);
3104}
3105
3106
3107/**
3108 * We had to do a DNS lookup. Convert the result (if any) and return
3109 * it.
3110 *
3111 * @param cls closure with the 'struct GNS_ResolverHandle'
3112 * @param addr one of the addresses of the host, NULL for the last address
3113 * @param addrlen length of the address
3114 */
3115static void
3116handle_dns_result (void *cls,
3117 const struct sockaddr *addr,
3118 socklen_t addrlen)
3119{
3120 struct GNS_ResolverHandle *rh = cls;
3121 const struct sockaddr_in *sa4;
3122 const struct sockaddr_in6 *sa6;
3123
3124 rh->std_resolve = NULL;
3125 if (NULL == addr)
3126 {
3127 transmit_lookup_dns_result (rh);
3128 return;
3129 }
3130 switch (addr->sa_family)
3131 {
3132 case AF_INET:
3133 sa4 = (const struct sockaddr_in *) addr;
3134 add_dns_result (rh,
3135 0 /* expiration time is unknown */,
3136 GNUNET_DNSPARSER_TYPE_A,
3137 sizeof (struct in_addr),
3138 &sa4->sin_addr);
3139 break;
3140 case AF_INET6:
3141 sa6 = (const struct sockaddr_in6 *) addr;
3142 add_dns_result (rh,
3143 0 /* expiration time is unknown */,
3144 GNUNET_DNSPARSER_TYPE_AAAA,
3145 sizeof (struct in6_addr),
3146 &sa6->sin6_addr);
3147 break;
3148 default:
3149 GNUNET_break (0);
3150 break;
3151 }
3152}
3153
3154
3155/**
3156 * Task scheduled to continue with the resolution process.
3157 *
3158 * @param cls the 'struct GNS_ResolverHandle' of the resolution
3159 * @param tc task context
3160 */
3161static void
3162recursive_resolution (void *cls,
3163 const struct GNUNET_SCHEDULER_TaskContext *tc);
3164
3165
3166/**
3167 * Function called with the result of a DNS resolution.
3168 *
3169 * @param cls the request handle of the resolution that
3170 * we were attempting to make
3171 * @param rs socket that received the response
3172 * @param dns dns response, never NULL
3173 * @param dns_len number of bytes in 'dns'
3174 */
3175static void
3176dns_result_parser (void *cls,
3177 struct GNUNET_DNSSTUB_RequestSocket *rs,
3178 const struct GNUNET_TUN_DnsHeader *dns,
3179 size_t dns_len)
3180{
3181 struct GNS_ResolverHandle *rh = cls;
3182 struct GNUNET_DNSPARSER_Packet *p;
3183
3184 rh->dns_request = NULL;
3185 GNUNET_SCHEDULER_cancel (rh->task_id);
3186 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3187 p = GNUNET_DNSPARSER_parse ((const char *) dns,
3188 dns_len);
3189 if (NULL == p)
3190 {
3191 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3192 _("Failed to parse DNS response\n"));
3193 rh->proc (rh->proc_cls, 0, NULL);
3194 GNS_resolver_lookup_cancel (rh);
3195 return;
3196 }
3197 // FIXME:
3198 // Check if the packet is the final answer, or
3199 // just pointing us to another NS or another name (CNAME), or another domain (DNAME);
3200 // then do the right thing (TM) -- possibly using "recursive_dns_resolution".
3201 GNUNET_break (0);
3202 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3203 _("NOT IMPLEMENTED\n"));
3204 rh->proc (rh->proc_cls, 0, NULL);
3205 GNS_resolver_lookup_cancel (rh);
3206
3207
3208 GNUNET_DNSPARSER_free_packet (p);
3209}
3210
3211
3212/**
3213 * Perform recursive DNS resolution. Asks the given DNS resolver to
3214 * resolve "rh->dns_name", possibly recursively proceeding following
3215 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
3216 * we find the answer.
3217 *
3218 * @param rh resolution information
3219 */
3220static void
3221recursive_dns_resolution (struct GNS_ResolverHandle *rh)
3222{
3223 struct AuthorityChain *ac;
3224 socklen_t sa_len;
3225 struct GNUNET_DNSPARSER_Query *query;
3226 struct GNUNET_DNSPARSER_Packet *p;
3227 char *dns_request;
3228 size_t dns_request_length;
3229
3230 ac = rh->ac_tail;
3231 GNUNET_assert (NULL != ac);
3232 GNUNET_assert (GNUNET_NO == ac->gns_authority);
3233 switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
3234 {
3235 case AF_INET:
3236 sa_len = sizeof (struct sockaddr_in);
3237 break;
3238 case AF_INET6:
3239 sa_len = sizeof (struct sockaddr_in6);
3240 break;
3241 default:
3242 GNUNET_break (0);
3243 rh->proc (rh->proc_cls, 0, NULL);
3244 GNS_resolver_lookup_cancel (rh);
3245 return;
3246 }
3247 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
3248 query->name = GNUNET_strdup (ac->label);
3249 query->type = rh->record_type;
3250 query->class = GNUNET_DNSPARSER_CLASS_INTERNET;
3251 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
3252 p->queries = query;
3253 p->num_queries = 1;
3254 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3255 UINT16_MAX);
3256 p->flags.opcode = GNUNET_DNSPARSER_OPCODE_QUERY;
3257 p->flags.recursion_desired = 1;
3258 if (GNUNET_OK !=
3259 GNUNET_DNSPARSER_pack (p, 1024, &dns_request, &dns_request_length))
3260 {
3261 GNUNET_break (0);
3262 rh->proc (rh->proc_cls, 0, NULL);
3263 GNS_resolver_lookup_cancel (rh);
3264 }
3265 else
3266 {
3267 rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle,
3268 (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip,
3269 sa_len,
3270 dns_request,
3271 dns_request_length,
3272 &dns_result_parser,
3273 rh);
3274 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
3275 &fail_resolution,
3276 rh);
3277 }
3278 GNUNET_free (dns_request);
3279 GNUNET_DNSPARSER_free_packet (p);
3280}
3281
3282
3283/**
3284 * Process a records that were decrypted from a block.
3285 *
3286 * @param cls closure with the 'struct GNS_ResolverHandle'
3287 * @param rd_count number of entries in @a rd array
3288 * @param rd array of records with data to store
3289 */
3290static void
3291handle_gns_resolution_result (void *cls,
3292 unsigned int rd_count,
3293 const struct GNUNET_NAMESTORE_RecordData *rd)
3294{
3295 struct GNS_ResolverHandle *rh = cls;
3296
3297 // FIXME: not implemented
3298 // if this was the last label, return 'rd' to application
3299 // (possibly first checking about converting records
3300 // to requested type, if possible).
3301 // if not, look for PKEY, CNAME, DNAME or NS to extend
3302 // auth chain and continue with recursion
3303 GNUNET_break (0);
3304 rh->proc (rh->proc_cls, 0, NULL);
3305 GNS_resolver_lookup_cancel (rh);
3306}
3307
3308
3309/**
3310 * Function called once the namestore has completed the request for
3311 * caching a block.
3312 *
3313 * @param cls closure with the 'struct GNS_ResolverHandle'
3314 * @param success #GNUNET_OK on success
3315 * @param emsg error message
3316 */
3317static void
3318namestore_cache_continuation (void *cls,
3319 int32_t success,
3320 const char *emsg)
3321{
3322 struct GNS_ResolverHandle *rh = cls;
3323
3324 rh->namestore_qe = NULL;
3325 if (NULL != emsg)
3326 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3327 _("Failed to cache GNS resolution: %s\n"),
3328 emsg);
3329}
3330
3331
3332/**
3333 * Iterator called on each result obtained for a DHT
3334 * operation that expects a reply
3335 *
3336 * @param cls closure with the 'struct GNS_ResolverHandle'
3337 * @param exp when will this value expire
3338 * @param key key of the result
3339 * @param get_path peers on reply path (or NULL if not recorded)
3340 * [0] = datastore's first neighbor, [length - 1] = local peer
3341 * @param get_path_length number of entries in get_path
3342 * @param put_path peers on the PUT path (or NULL if not recorded)
3343 * [0] = origin, [length - 1] = datastore
3344 * @param put_path_length number of entries in get_path
3345 * @param type type of the result
3346 * @param size number of bytes in data
3347 * @param data pointer to the result data
3348 */
3349static void
3350handle_dht_response (void *cls,
3351 struct GNUNET_TIME_Absolute exp,
3352 const struct GNUNET_HashCode * key,
3353 const struct GNUNET_PeerIdentity *get_path,
3354 unsigned int get_path_length,
3355 const struct GNUNET_PeerIdentity *put_path,
3356 unsigned int put_path_length,
3357 enum GNUNET_BLOCK_Type type,
3358 size_t size, const void *data)
3359{
3360 struct GNS_ResolverHandle *rh = cls;
3361 struct AuthorityChain *ac = rh->ac_tail;
3362 const struct GNUNET_NAMESTORE_Block *block;
3363
3364 GNUNET_DHT_get_stop (rh->get_handle);
3365 rh->get_handle = NULL;
3366 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
3367 rh->dht_heap_node = NULL;
3368 if (size < sizeof (struct GNUNET_NAMESTORE_Block))
3369 {
3370 /* how did this pass DHT block validation!? */
3371 GNUNET_break (0);
3372 rh->proc (rh->proc_cls, 0, NULL);
3373 GNS_resolver_lookup_cancel (rh);
3374 return;
3375 }
3376 block = data;
3377 if (size !=
3378 ntohs (block->purpose.size) +
3379 sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
3380 sizeof (struct GNUNET_CRYPTO_EccSignature))
3381 {
3382 /* how did this pass DHT block validation!? */
3383 GNUNET_break (0);
3384 rh->proc (rh->proc_cls, 0, NULL);
3385 GNS_resolver_lookup_cancel (rh);
3386 return;
3387 }
3388 if (GNUNET_OK !=
3389 GNUNET_NAMESTORE_block_decrypt (block,
3390 &ac->authority_info.gns_authority,
3391 ac->label,
3392 &handle_gns_resolution_result,
3393 rh))
3394 {
3395 GNUNET_break_op (0); /* block was ill-formed */
3396 rh->proc (rh->proc_cls, 0, NULL);
3397 GNS_resolver_lookup_cancel (rh);
3398 return;
3399 }
3400 /* Cache well-formed blocks */
3401 rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
3402 block,
3403 &namestore_cache_continuation,
3404 rh);
3405}
3406
3407
3408/**
3409 * Process a record that was stored in the namestore.
3410 *
3411 * @param cls closure with the 'struct GNS_ResolverHandle'
3412 * @param block block that was stored in the namestore
3413 */
3414static void
3415handle_namestore_block_response (void *cls,
3416 const struct GNUNET_NAMESTORE_Block *block)
3417{
3418 struct GNS_ResolverHandle *rh = cls;
3419 struct GNS_ResolverHandle *rx;
3420 struct AuthorityChain *ac = rh->ac_tail;
3421 const char *label = ac->label;
3422 const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
3423 struct GNUNET_HashCode query;
3424
3425 GNUNET_NAMESTORE_query_from_public_key (auth,
3426 label,
3427 &query);
3428 rh->namestore_qe = NULL;
3429 if (NULL == block)
3430 {
3431 /* Namestore knows nothing; try DHT lookup */
3432 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
3433 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
3434 &query,
3435 DHT_GNS_REPLICATION_LEVEL,
3436 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
3437 NULL, 0,
3438 &handle_dht_response, rh);
3439 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
3440 rh,
3441 GNUNET_TIME_absolute_get ().abs_value_us);
3442 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
3443 {
3444 /* fail longest-standing DHT request */
3445 rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
3446 rx->proc (rx->proc_cls, 0, NULL);
3447 GNS_resolver_lookup_cancel (rx);
3448 }
3449 return;
3450 }
3451 if (GNUNET_OK !=
3452 GNUNET_NAMESTORE_block_decrypt (block,
3453 auth,
3454 label,
3455 &handle_gns_resolution_result,
3456 rh))
3457 {
3458 GNUNET_break_op (0); /* block was ill-formed */
3459 rh->proc (rh->proc_cls, 0, NULL);
3460 GNS_resolver_lookup_cancel (rh);
3461 return;
3462 }
3463}
3464
3465
3466/**
3467 * Lookup tail of our authority chain in the namestore.
3468 *
3469 * @param rh query we are processing
3470 */
3471static void
3472recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
3473{
3474 struct AuthorityChain *ac = rh->ac_tail;
3475 struct GNUNET_HashCode query;
3476
3477 GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
3478 ac->label,
3479 &query);
3480 rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
3481 &query,
3482 &handle_namestore_block_response,
3483 rh);
3484}
3485
3486
3487/**
3488 * Task scheduled to continue with the resolution process.
3489 *
3490 * @param cls the 'struct GNS_ResolverHandle' of the resolution
3491 * @param tc task context
3492 */
3493static void
3494recursive_resolution (void *cls,
3495 const struct GNUNET_SCHEDULER_TaskContext *tc)
3496{
3497 struct GNS_ResolverHandle *rh = cls;
3498
3499 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3500 if (MAX_RECURSION < rh->loop_limiter++)
3501 {
3502 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3503 "Encountered unbounded recursion resolving `%s'\n",
3504 rh->name);
3505 rh->proc (rh->proc_cls, 0, NULL);
3506 GNS_resolver_lookup_cancel (rh);
3507 return;
3508 }
3509 if (GNUNET_YES == rh->ac_tail->gns_authority)
3510 recursive_gns_resolution_namestore (rh);
3511 else
3512 recursive_dns_resolution (rh);
3513}
2887 3514
2888 3515
2889/** 3516/**
@@ -2907,167 +3534,166 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
2907 int only_cached, 3534 int only_cached,
2908 GNS_ResultProcessor proc, void *proc_cls) 3535 GNS_ResultProcessor proc, void *proc_cls)
2909{ 3536{
2910 return NULL; 3537 struct GNS_ResolverHandle *rh;
2911#if 0 3538 struct AuthorityChain *ac;
2912 struct ResolverHandle *rh; 3539 char *x;
2913 struct RecordLookupHandle* rlh; 3540 char *y;
2914 char string_hash[GNUNET_DNSPARSER_MAX_LABEL_LENGTH]; 3541 char *pkey;
2915 char nzkey[GNUNET_DNSPARSER_MAX_LABEL_LENGTH]; 3542
2916 char* nzkey_ptr = nzkey; 3543 rh = GNUNET_new (struct GNS_ResolverHandle);
2917 3544 GNUNET_CONTAINER_DLL_insert (rlh_head,
2918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3545 rlh_tail,
2919 "Starting resolution for `%s' (type=%d) with timeout %s!\n", 3546 rh);
2920 name, record_type, 3547 rh->authority_zone = *zone;
2921 GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES)); 3548 rh->proc = proc;
2922 3549 rh->proc_cls = proc_cls;
2923 if ((is_canonical ((char*)name) == GNUNET_YES) &&
2924 (strcmp(GNUNET_GNS_TLD, name) != 0))
2925 {
2926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2927 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2928 proc(cls, 0, NULL);
2929 return;
2930 }
2931
2932 rlh = GNUNET_malloc (sizeof(struct RecordLookupHandle));
2933 rh = GNUNET_malloc (sizeof (struct ResolverHandle));
2934 rh->authority = zone;
2935 rh->id = rid_gen++;
2936 rh->proc_cls = rlh;
2937 rh->priv_key = key;
2938 rh->timeout = timeout;
2939 rh->private_local_zone = pzone;
2940 rh->only_cached = only_cached; 3550 rh->only_cached = only_cached;
2941 3551 rh->record_type = record_type;
2942 GNUNET_CONTAINER_DLL_insert (rlh_head, rlh_tail, rh); 3552 rh->name = GNUNET_strdup (name);
2943 3553 rh->name_resolution_pos = strlen (name);
2944 if (NULL == key) 3554 if (NULL != shorten_key)
2945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2946 "No shorten key for resolution\n");
2947
2948 if (timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
2949 { 3555 {
2950 /* 3556 rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
2951 * Set timeout for authority lookup phase to 1/2 3557 *rh->shorten_key = *shorten_key;
2952 */
2953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2954 "Timeout for lookup set to %s/2\n",
2955 GNUNET_STRINGS_relative_time_to_string (rh->timeout, GNUNET_YES));
2956 rh->timeout_task = GNUNET_SCHEDULER_add_delayed (
2957 GNUNET_TIME_relative_divide(timeout, 2),
2958 &handle_lookup_timeout,
2959 rh);
2960 rh->timeout_cont = &dht_authority_lookup_timeout;
2961 rh->timeout_cont_cls = rh;
2962 } 3558 }
2963 else
2964 {
2965 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2966 rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2967 }
2968
2969 if (strcmp(GNUNET_GNS_TLD, name) == 0)
2970 {
2971 /**
2972 * Only '.gads' given
2973 */
2974 strcpy (rh->name, "\0");
2975 }
2976 else
2977 {
2978 if (is_zkey_tld(name) == GNUNET_YES)
2979 {
2980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2981 "TLD is zkey\n");
2982 /**
2983 * This is a zkey tld
2984 * build hash and use as initial authority
2985 */
2986 memset(rh->name, 0,
2987 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2988 memcpy(rh->name, name,
2989 strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2990 pop_tld (rh->name, string_hash);
2991
2992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2993 "ZKEY is %s!\n", string_hash);
2994
2995 GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2996 3559
2997 if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey, 3560 if ( ( (GNUNET_YES == is_canonical (name)) &&
2998 &rh->authority)) 3561 (0 != strcmp (GNUNET_GNS_TLD, name)) ) ||
2999 { 3562 ( (GNUNET_YES != is_gads_tld (name)) &&
3000 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3563 (GNUNET_YES != is_zkey_tld (name)) ) )
3001 "Cannot convert ZKEY `%s' to hash!\n", string_hash); 3564 {
3002 3565 /* use standard DNS lookup */
3003 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task) 3566 int af;
3004 GNUNET_SCHEDULER_cancel (rh->timeout_task);
3005 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3006 GNUNET_free (rh);
3007 GNUNET_free (rlh);
3008 proc (cls, 0, NULL);
3009 return;
3010 }
3011 3567
3012 } 3568 switch (record_type)
3013 else if (is_gads_tld (name) == GNUNET_YES)
3014 { 3569 {
3015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3570 case GNUNET_DNSPARSER_TYPE_A:
3016 "TLD is gads\n"); 3571 af = AF_INET;
3017 /** 3572 break;
3018 * Presumably GADS tld 3573 case GNUNET_DNSPARSER_TYPE_AAAA:
3019 */ 3574 af = AF_INET6;
3020 memcpy (rh->name, name, 3575 break;
3021 strlen (name) - strlen(GNUNET_GNS_TLD) - 1); 3576 default:
3022 rh->name[strlen (name) - strlen(GNUNET_GNS_TLD) - 1] = '\0'; 3577 af = AF_UNSPEC;
3578 break;
3023 } 3579 }
3024 else 3580 rh->std_resolve = GNUNET_RESOLVER_ip_get (name,
3581 af,
3582 DNS_LOOKUP_TIMEOUT,
3583 &handle_dns_result,
3584 rh);
3585 return rh;
3586 }
3587 if (is_zkey_tld (name))
3588 {
3589 /* Name ends with ".zkey", try to replace authority zone with zkey
3590 authority */
3591 GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
3592 x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
3593 y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
3594 GNUNET_asprintf (&pkey,
3595 "%s%s",
3596 x, y);
3597 if ( (NULL == x) ||
3598 (NULL == y) ||
3599 (GNUNET_OK !=
3600 GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
3601 strlen (pkey),
3602 &rh->authority_zone)) )
3025 { 3603 {
3026 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3604 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3027 _("Not a GADS TLD: `%s'\n"), 3605 _("Hostname `%s' is not well-formed, resolution fails\n"),
3028 name); 3606 name);
3029 if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task) 3607 rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
3030 GNUNET_SCHEDULER_cancel (rh->timeout_task);
3031 GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3032 GNUNET_free (rh);
3033 GNUNET_free (rlh);
3034 proc (cls, 0, NULL);
3035 return;
3036 } 3608 }
3609 GNUNET_free_non_null (x);
3610 GNUNET_free_non_null (y);
3611 GNUNET_free (pkey);
3037 } 3612 }
3038 3613 else
3039 /** 3614 {
3040 * Initialize authority chain 3615 /* Name ends with ".gnu", eat ".gnu" and continue with resolution */
3041 */ 3616 GNUNET_free (resolver_lookup_get_next_label (rh));
3042 rh->authority_chain_head = GNUNET_malloc (sizeof(struct AuthorityChain)); 3617 }
3043 rh->authority_chain_tail = rh->authority_chain_head; 3618 ac = GNUNET_new (struct AuthorityChain);
3044 rh->authority_chain_head->zone = rh->authority; 3619 ac->rh = rh;
3045 strcpy (rh->authority_chain_head->name, ""); 3620 ac->label = resolver_lookup_get_next_label (rh);
3046 3621 if (NULL == ac->label)
3047 /** 3622 /* name was just "gnu", so we default to label '+' */
3048 * Copy original query into lookup handle 3623 ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
3049 */ 3624 ac->gns_authority = GNUNET_YES;
3050 rlh->record_type = record_type; 3625 ac->authority_info.gns_authority = rh->authority_zone;
3051 memset(rlh->name, 0, strlen(name) + 1); 3626 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
3052 strcpy(rlh->name, name); 3627 rh->ac_tail,
3053 rlh->proc = proc; 3628 ac);
3054 rlh->proc_cls = cls; 3629 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
3055 3630 rh);
3056 rh->proc = &handle_delegation_ns; 3631 return rh;
3057 resolve_delegation_ns (rh);
3058#endif
3059} 3632}
3060 3633
3061 3634
3062
3063/** 3635/**
3064 * Cancel active resolution (i.e. client disconnected). 3636 * Cancel active resolution (i.e. client disconnected).
3065 * 3637 *
3066 * @param h resolution to abort 3638 * @param rh resolution to abort
3067 */ 3639 */
3068void 3640void
3069GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *h) 3641GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
3070{ 3642{
3643 struct DnsResult *dr;
3644 struct AuthorityChain *ac;
3645
3646 GNUNET_CONTAINER_DLL_remove (rlh_head,
3647 rlh_tail,
3648 rh);
3649 while (NULL != (ac = rh->ac_head))
3650 {
3651 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
3652 rh->ac_tail,
3653 ac);
3654 GNUNET_free (ac->label);
3655 GNUNET_free (ac);
3656 }
3657 if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
3658 {
3659 GNUNET_SCHEDULER_cancel (rh->task_id);
3660 rh->task_id = GNUNET_SCHEDULER_NO_TASK;
3661 }
3662 if (NULL != rh->get_handle)
3663 {
3664 GNUNET_DHT_get_stop (rh->get_handle);
3665 rh->get_handle = NULL;
3666 }
3667 if (NULL != rh->dht_heap_node)
3668 {
3669 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
3670 rh->dht_heap_node = NULL;
3671 }
3672 if (NULL != rh->dns_request)
3673 {
3674 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
3675 rh->dns_request = NULL;
3676 }
3677 if (NULL != rh->namestore_qe)
3678 {
3679 GNUNET_NAMESTORE_cancel (rh->namestore_qe);
3680 rh->namestore_qe = NULL;
3681 }
3682 if (NULL != rh->std_resolve)
3683 {
3684 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
3685 rh->std_resolve = NULL;
3686 }
3687 while (NULL != (dr = rh->dns_result_head))
3688 {
3689 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
3690 rh->dns_result_tail,
3691 dr);
3692 GNUNET_free (dr);
3693 }
3694 GNUNET_free_non_null (rh->shorten_key);
3695 GNUNET_free (rh->name);
3696 GNUNET_free (rh);
3071} 3697}
3072 3698
3073 3699
@@ -3118,6 +3744,15 @@ GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
3118void 3744void
3119GNS_resolver_done () 3745GNS_resolver_done ()
3120{ 3746{
3747 struct GNS_ResolverHandle *rh;
3748
3749 /* abort active resolutions */
3750 while (NULL != (rh = rlh_head))
3751 {
3752 rh->proc (rh->proc_cls, 0, NULL);
3753 GNS_resolver_lookup_cancel (rh);
3754 }
3755 /* abort active shorten operations */
3121 while (NULL != gph_head) 3756 while (NULL != gph_head)
3122 free_get_pseu_authority_handle (gph_head); 3757 free_get_pseu_authority_handle (gph_head);
3123 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap); 3758 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);