aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dns/dnsstub.c683
-rw-r--r--src/dns/gnunet-service-dns.c43
-rw-r--r--src/dns/gnunet-zoneimport.c24
-rw-r--r--src/exit/gnunet-daemon-exit.c29
-rw-r--r--src/gns/gnunet-dns2gns.c19
-rw-r--r--src/gns/gnunet-service-gns_resolver.c1072
-rw-r--r--src/gns/test_gns_lookup.conf2
-rw-r--r--src/include/gnunet_dnsstub_lib.h85
-rw-r--r--src/namestore/gnunet-zoneimport.c35
9 files changed, 1107 insertions, 885 deletions
diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c
index 6aa2d7b8f..6eb3612c2 100644
--- a/src/dns/dnsstub.c
+++ b/src/dns/dnsstub.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V. 3 Copyright (C) 2012, 2018 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -28,20 +28,15 @@
28#include "gnunet_dnsstub_lib.h" 28#include "gnunet_dnsstub_lib.h"
29 29
30/** 30/**
31 * Timeout for an external (Internet-DNS) DNS resolution
32 */
33#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
34
35/**
36 * Timeout for retrying DNS queries. 31 * Timeout for retrying DNS queries.
37 */ 32 */
38#define DNS_RETRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) 33#define DNS_RETRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
39 34
35
40/** 36/**
41 * How many DNS sockets do we open at most at the same time? 37 * DNS Server used for resolution.
42 * (technical socket maximum is this number x2 for IPv4+IPv6)
43 */ 38 */
44#define DNS_SOCKET_MAX 128 39struct DnsServer;
45 40
46 41
47/** 42/**
@@ -81,19 +76,14 @@ struct GNUNET_DNSSTUB_RequestSocket
81 struct GNUNET_SCHEDULER_Task *retry_task; 76 struct GNUNET_SCHEDULER_Task *retry_task;
82 77
83 /** 78 /**
84 * When should this request time out? 79 * Next address we sent the DNS request to.
85 */
86 struct GNUNET_TIME_Absolute timeout;
87
88 /**
89 * Address we sent the DNS request to.
90 */ 80 */
91 struct sockaddr_storage addr; 81 struct DnsServer *ds_pos;
92 82
93 /** 83 /**
94 * Number of bytes in @e addr. 84 * Context this request executes in.
95 */ 85 */
96 socklen_t addrlen; 86 struct GNUNET_DNSSTUB_Context *ctx;
97 87
98 /** 88 /**
99 * Query we sent to @e addr. 89 * Query we sent to @e addr.
@@ -109,6 +99,29 @@ struct GNUNET_DNSSTUB_RequestSocket
109 99
110 100
111/** 101/**
102 * DNS Server used for resolution.
103 */
104struct DnsServer
105{
106
107 /**
108 * Kept in a DLL.
109 */
110 struct DnsServer *next;
111
112 /**
113 * Kept in a DLL.
114 */
115 struct DnsServer *prev;
116
117 /**
118 * IP address of the DNS resolver.
119 */
120 struct sockaddr_storage ss;
121};
122
123
124/**
112 * Handle to the stub resolver. 125 * Handle to the stub resolver.
113 */ 126 */
114struct GNUNET_DNSSTUB_Context 127struct GNUNET_DNSSTUB_Context
@@ -117,13 +130,28 @@ struct GNUNET_DNSSTUB_Context
117 /** 130 /**
118 * Array of all open sockets for DNS requests. 131 * Array of all open sockets for DNS requests.
119 */ 132 */
120 struct GNUNET_DNSSTUB_RequestSocket sockets[DNS_SOCKET_MAX]; 133 struct GNUNET_DNSSTUB_RequestSocket *sockets;
134
135 /**
136 * DLL of DNS resolvers we use.
137 */
138 struct DnsServer *dns_head;
139
140 /**
141 * DLL of DNS resolvers we use.
142 */
143 struct DnsServer *dns_tail;
144
145 /**
146 * How frequently do we retry requests?
147 */
148 struct GNUNET_TIME_Relative retry_freq;
121 149
122 /** 150 /**
123 * IP address to use for the DNS server if we are a DNS exit service 151 * Length of @e sockets array.
124 * (for VPN via cadet); otherwise NULL.
125 */ 152 */
126 char *dns_exit; 153 unsigned int num_sockets;
154
127}; 155};
128 156
129 157
@@ -212,33 +240,21 @@ open_socket (int af)
212 240
213 241
214/** 242/**
215 * Read a DNS response from the (unhindered) UDP-Socket
216 *
217 * @param cls socket to read from
218 */
219static void
220read_response (void *cls);
221
222
223/**
224 * Get a socket of the specified address family to send out a 243 * Get a socket of the specified address family to send out a
225 * UDP DNS request to the Internet. 244 * UDP DNS request to the Internet.
226 * 245 *
227 * @param ctx the DNSSTUB context 246 * @param ctx the DNSSTUB context
228 * @param af desired address family 247 * @return NULL on error
229 * @return NULL on error (given AF not "supported")
230 */ 248 */
231static struct GNUNET_DNSSTUB_RequestSocket * 249static struct GNUNET_DNSSTUB_RequestSocket *
232get_request_socket (struct GNUNET_DNSSTUB_Context *ctx, 250get_request_socket (struct GNUNET_DNSSTUB_Context *ctx)
233 int af)
234{ 251{
235 struct GNUNET_DNSSTUB_RequestSocket *rs; 252 struct GNUNET_DNSSTUB_RequestSocket *rs;
236 struct GNUNET_NETWORK_FDSet *rset;
237 253
238 for (unsigned int i=0;i<256;i++) 254 for (unsigned int i=0;i<256;i++)
239 { 255 {
240 rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256 rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
241 DNS_SOCKET_MAX)]; 257 ctx->num_sockets)];
242 if (NULL == rs->rc) 258 if (NULL == rs->rc)
243 break; 259 break;
244 } 260 }
@@ -246,25 +262,10 @@ get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
246 { 262 {
247 /* signal "failure" */ 263 /* signal "failure" */
248 rs->rc (rs->rc_cls, 264 rs->rc (rs->rc_cls,
249 rs,
250 NULL, 265 NULL,
251 0); 266 0);
252 rs->rc = NULL; 267 rs->rc = NULL;
253 } 268 }
254 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
255 switch (af)
256 {
257 case AF_INET:
258 if (NULL == rs->dnsout4)
259 rs->dnsout4 = open_socket (AF_INET);
260 break;
261 case AF_INET6:
262 if (NULL == rs->dnsout6)
263 rs->dnsout6 = open_socket (AF_INET6);
264 break;
265 default:
266 return NULL;
267 }
268 if (NULL != rs->read_task) 269 if (NULL != rs->read_task)
269 { 270 {
270 GNUNET_SCHEDULER_cancel (rs->read_task); 271 GNUNET_SCHEDULER_cancel (rs->read_task);
@@ -280,194 +281,7 @@ get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
280 GNUNET_free (rs->request); 281 GNUNET_free (rs->request);
281 rs->request = NULL; 282 rs->request = NULL;
282 } 283 }
283 if ( (NULL == rs->dnsout4) && 284 rs->ctx = ctx;
284 (NULL == rs->dnsout6) )
285 return NULL;
286 rset = GNUNET_NETWORK_fdset_create ();
287 if (NULL != rs->dnsout4)
288 GNUNET_NETWORK_fdset_set (rset,
289 rs->dnsout4);
290 if (NULL != rs->dnsout6)
291 GNUNET_NETWORK_fdset_set (rset,
292 rs->dnsout6);
293 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
294 REQUEST_TIMEOUT,
295 rset,
296 NULL,
297 &read_response,
298 rs);
299 GNUNET_NETWORK_fdset_destroy (rset);
300 return rs;
301}
302
303
304/**
305 * Task to (re)transmit the DNS query, possibly repeatedly until
306 * we succeed.
307 *
308 * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *`
309 */
310static void
311transmit_query (void *cls)
312{
313 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
314 struct GNUNET_NETWORK_Handle *ret;
315
316 rs->retry_task = NULL;
317 ret = (NULL != rs->dnsout4) ? rs->dnsout4 : rs->dnsout6;
318 GNUNET_assert (NULL != ret);
319 if (GNUNET_SYSERR ==
320 GNUNET_NETWORK_socket_sendto (ret,
321 rs->request,
322 rs->request_len,
323 (struct sockaddr *) &rs->addr,
324 rs->addrlen))
325 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
326 _("Failed to send DNS request to %s\n"),
327 GNUNET_a2s ((struct sockaddr *) &rs->addr,
328 rs->addrlen));
329 else
330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
331 _("Sent DNS request to %s\n"),
332 GNUNET_a2s ((struct sockaddr *) &rs->addr,
333 rs->addrlen));
334 rs->retry_task = GNUNET_SCHEDULER_add_delayed (DNS_RETRANSMIT_DELAY,
335 &transmit_query,
336 rs);
337}
338
339
340/**
341 * Perform DNS resolution.
342 *
343 * @param ctx stub resolver to use
344 * @param sa the socket address
345 * @param sa_len the length of @a sa
346 * @param request DNS request to transmit
347 * @param request_len number of bytes in @a request
348 * @param rc function to call with result
349 * @param rc_cls closure for @a rc
350 * @return socket used for the request, NULL on error
351 */
352struct GNUNET_DNSSTUB_RequestSocket *
353GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
354 const struct sockaddr *sa,
355 socklen_t sa_len,
356 const void *request,
357 size_t request_len,
358 GNUNET_DNSSTUB_ResultCallback rc,
359 void *rc_cls)
360{
361 struct GNUNET_DNSSTUB_RequestSocket *rs;
362
363 if (NULL == (rs = get_request_socket (ctx,
364 sa->sa_family)))
365 return NULL;
366 GNUNET_assert (NULL == rs->rc);
367 GNUNET_memcpy (&rs->addr,
368 sa,
369 sa_len);
370 rs->addrlen = sa_len;
371 rs->rc = rc;
372 rs->rc_cls = rc_cls;
373 rs->request = GNUNET_memdup (request,
374 request_len);
375 rs->request_len = request_len;
376 rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query,
377 rs);
378 return rs;
379}
380
381
382/**
383 * Perform DNS resolution using our default IP from init.
384 *
385 * @param ctx stub resolver to use
386 * @param request DNS request to transmit
387 * @param request_len number of bytes in msg
388 * @param rc function to call with result
389 * @param rc_cls closure for 'rc'
390 * @return socket used for the request, NULL on error
391 */
392struct GNUNET_DNSSTUB_RequestSocket *
393GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
394 const void *request,
395 size_t request_len,
396 GNUNET_DNSSTUB_ResultCallback rc,
397 void *rc_cls)
398{
399 int af;
400 struct sockaddr_in v4;
401 struct sockaddr_in6 v6;
402 struct sockaddr *sa;
403 socklen_t salen;
404 struct GNUNET_NETWORK_Handle *dnsout;
405 struct GNUNET_DNSSTUB_RequestSocket *rs;
406
407 memset (&v4, 0, sizeof (v4));
408 memset (&v6, 0, sizeof (v6));
409 if (1 == inet_pton (AF_INET,
410 ctx->dns_exit,
411 &v4.sin_addr))
412 {
413 salen = sizeof (v4);
414 v4.sin_family = AF_INET;
415 v4.sin_port = htons (53);
416#if HAVE_SOCKADDR_IN_SIN_LEN
417 v4.sin_len = (u_char) salen;
418#endif
419 sa = (struct sockaddr *) &v4;
420 af = AF_INET;
421 }
422 else if (1 == inet_pton (AF_INET6,
423 ctx->dns_exit,
424 &v6.sin6_addr))
425 {
426 salen = sizeof (v6);
427 v6.sin6_family = AF_INET6;
428 v6.sin6_port = htons (53);
429#if HAVE_SOCKADDR_IN_SIN_LEN
430 v6.sin6_len = (u_char) salen;
431#endif
432 sa = (struct sockaddr *) &v6;
433 af = AF_INET6;
434 }
435 else
436 {
437 GNUNET_break (0);
438 return NULL;
439 }
440 if (NULL == (rs = get_request_socket (ctx,
441 af)))
442 return NULL;
443 GNUNET_assert (NULL == rs->rc);
444 if (NULL != rs->dnsout4)
445 dnsout = rs->dnsout4;
446 else
447 dnsout = rs->dnsout6;
448 if (NULL == dnsout)
449 {
450 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
451 _("Configured DNS exit `%s' is not working / valid.\n"),
452 ctx->dns_exit);
453 return NULL;
454 }
455 GNUNET_memcpy (&rs->addr,
456 sa,
457 salen);
458 rs->addrlen = salen;
459 rs->rc = rc;
460 rs->rc_cls = rc_cls;
461 if (GNUNET_SYSERR ==
462 GNUNET_NETWORK_socket_sendto (dnsout,
463 request,
464 request_len,
465 sa,
466 salen))
467 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
468 _("Failed to send DNS request to %s\n"),
469 GNUNET_a2s (sa, salen));
470 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
471 return rs; 285 return rs;
472} 286}
473 287
@@ -484,9 +298,7 @@ static int
484do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs, 298do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
485 struct GNUNET_NETWORK_Handle *dnsout) 299 struct GNUNET_NETWORK_Handle *dnsout)
486{ 300{
487 struct sockaddr_storage addr; 301 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
488 socklen_t addrlen;
489 struct GNUNET_TUN_DnsHeader *dns;
490 ssize_t r; 302 ssize_t r;
491 int len; 303 int len;
492 304
@@ -507,9 +319,15 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
507 len); 319 len);
508 { 320 {
509 unsigned char buf[len] GNUNET_ALIGN; 321 unsigned char buf[len] GNUNET_ALIGN;
322 int found;
323 struct sockaddr_storage addr;
324 socklen_t addrlen;
325 struct GNUNET_TUN_DnsHeader *dns;
510 326
511 addrlen = sizeof (addr); 327 addrlen = sizeof (addr);
512 memset (&addr, 0, sizeof (addr)); 328 memset (&addr,
329 0,
330 sizeof (addr));
513 r = GNUNET_NETWORK_socket_recvfrom (dnsout, 331 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
514 buf, 332 buf,
515 sizeof (buf), 333 sizeof (buf),
@@ -522,6 +340,24 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
522 GNUNET_NETWORK_socket_close (dnsout); 340 GNUNET_NETWORK_socket_close (dnsout);
523 return GNUNET_SYSERR; 341 return GNUNET_SYSERR;
524 } 342 }
343 found = GNUNET_NO;
344 for (struct DnsServer *ds = ctx->dns_head; NULL != ds; ds = ds->next)
345 {
346 if (0 == memcmp (&addr,
347 &ds->ss,
348 GNUNET_MIN (sizeof (struct sockaddr_storage),
349 addrlen)))
350 {
351 found = GNUNET_YES;
352 break;
353 }
354 }
355 if (GNUNET_NO == found)
356 {
357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
358 "Received DNS response from server we never asked (ignored)");
359 return GNUNET_NO;
360 }
525 if (sizeof (struct GNUNET_TUN_DnsHeader) > r) 361 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
526 { 362 {
527 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -530,22 +366,15 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
530 return GNUNET_NO; 366 return GNUNET_NO;
531 } 367 }
532 dns = (struct GNUNET_TUN_DnsHeader *) buf; 368 dns = (struct GNUNET_TUN_DnsHeader *) buf;
533 if ( (addrlen != rs->addrlen) || 369 if (NULL == rs->rc)
534 (GNUNET_YES !=
535 GNUNET_TUN_sockaddr_cmp ((struct sockaddr *) &rs->addr,
536 (struct sockaddr *) &addr,
537 GNUNET_YES)) ||
538 (0 == GNUNET_TIME_absolute_get_remaining (rs->timeout).rel_value_us) )
539 { 370 {
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "Request timeout or invalid sender address; ignoring reply\n"); 372 "Request timeout or cancelled; ignoring reply\n");
542 return GNUNET_NO; 373 return GNUNET_NO;
543 } 374 }
544 if (NULL != rs->rc) 375 rs->rc (rs->rc_cls,
545 rs->rc (rs->rc_cls, 376 dns,
546 rs, 377 r);
547 dns,
548 r);
549 } 378 }
550 return GNUNET_OK; 379 return GNUNET_OK;
551} 380}
@@ -557,44 +386,21 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
557 * @param cls socket to read from 386 * @param cls socket to read from
558 */ 387 */
559static void 388static void
560read_response (void *cls) 389read_response (void *cls);
390
391
392/**
393 * Schedule #read_response() task for @a rs.
394 *
395 * @param rs request to schedule read operation for
396 */
397static void
398schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs)
561{ 399{
562 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
563 struct GNUNET_NETWORK_FDSet *rset; 400 struct GNUNET_NETWORK_FDSet *rset;
564 const struct GNUNET_SCHEDULER_TaskContext *tc;
565
566 rs->read_task = NULL;
567 tc = GNUNET_SCHEDULER_get_task_context ();
568 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
569 {
570 /* signal "failure" (from timeout) */
571 if (NULL != rs->rc)
572 {
573 rs->rc (rs->rc_cls,
574 rs,
575 NULL,
576 0);
577 rs->rc = NULL;
578 }
579 /* timeout */
580 cleanup_rs (rs);
581 return;
582 }
583 /* read and process ready sockets */
584 if ((NULL != rs->dnsout4) &&
585 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
586 rs->dnsout4)) &&
587 (GNUNET_SYSERR == do_dns_read (rs,
588 rs->dnsout4)))
589 rs->dnsout4 = NULL;
590 if ((NULL != rs->dnsout6) &&
591 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
592 rs->dnsout6)) &&
593 (GNUNET_SYSERR == do_dns_read (rs,
594 rs->dnsout6)))
595 rs->dnsout6 = NULL;
596 401
597 /* re-schedule read task */ 402 if (NULL != rs->read_task)
403 GNUNET_SCHEDULER_cancel (rs->read_task);
598 rset = GNUNET_NETWORK_fdset_create (); 404 rset = GNUNET_NETWORK_fdset_create ();
599 if (NULL != rs->dnsout4) 405 if (NULL != rs->dnsout4)
600 GNUNET_NETWORK_fdset_set (rset, 406 GNUNET_NETWORK_fdset_set (rset,
@@ -603,7 +409,7 @@ read_response (void *cls)
603 GNUNET_NETWORK_fdset_set (rset, 409 GNUNET_NETWORK_fdset_set (rset,
604 rs->dnsout6); 410 rs->dnsout6);
605 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, 411 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
606 GNUNET_TIME_absolute_get_remaining (rs->timeout), 412 GNUNET_TIME_UNIT_FOREVER_REL,
607 rset, 413 rset,
608 NULL, 414 NULL,
609 &read_response, 415 &read_response,
@@ -613,6 +419,151 @@ read_response (void *cls)
613 419
614 420
615/** 421/**
422 * Read a DNS response from the (unhindered) UDP-Socket
423 *
424 * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from
425 */
426static void
427read_response (void *cls)
428{
429 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
430 const struct GNUNET_SCHEDULER_TaskContext *tc;
431
432 rs->read_task = NULL;
433 tc = GNUNET_SCHEDULER_get_task_context ();
434 /* read and process ready sockets */
435 if ( (NULL != rs->dnsout4) &&
436 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
437 rs->dnsout4)) &&
438 (GNUNET_SYSERR ==
439 do_dns_read (rs,
440 rs->dnsout4)) )
441 rs->dnsout4 = NULL;
442 if ( (NULL != rs->dnsout6) &&
443 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
444 rs->dnsout6)) &&
445 (GNUNET_SYSERR ==
446 do_dns_read (rs,
447 rs->dnsout6)) )
448 rs->dnsout6 = NULL;
449 /* re-schedule read task */
450 schedule_read (rs);
451}
452
453
454/**
455 * Task to (re)transmit the DNS query, possibly repeatedly until
456 * we succeed.
457 *
458 * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *`
459 */
460static void
461transmit_query (void *cls)
462{
463 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
464 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
465 const struct sockaddr *sa;
466 socklen_t salen;
467 struct DnsServer *ds;
468 struct GNUNET_NETWORK_Handle *dnsout;
469
470 rs->retry_task = GNUNET_SCHEDULER_add_delayed (ctx->retry_freq,
471 &transmit_query,
472 rs);
473 ds = rs->ds_pos;
474 rs->ds_pos = ds->next;
475 if (NULL == rs->ds_pos)
476 rs->ds_pos = ctx->dns_head;
477 GNUNET_assert (NULL != ds);
478 dnsout = NULL;
479 switch (ds->ss.ss_family)
480 {
481 case AF_INET:
482 if (NULL == rs->dnsout4)
483 rs->dnsout4 = open_socket (AF_INET);
484 dnsout = rs->dnsout4;
485 sa = (const struct sockaddr *) &ds->ss;
486 salen = sizeof (struct sockaddr_in);
487 break;
488 case AF_INET6:
489 if (NULL == rs->dnsout6)
490 rs->dnsout6 = open_socket (AF_INET6);
491 dnsout = rs->dnsout6;
492 sa = (const struct sockaddr *) &ds->ss;
493 salen = sizeof (struct sockaddr_in6);
494 break;
495 default:
496 return;
497 }
498 if (NULL == dnsout)
499 {
500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
501 "Unable to use configure DNS server, skipping\n");
502 return;
503 }
504 if (GNUNET_SYSERR ==
505 GNUNET_NETWORK_socket_sendto (dnsout,
506 rs->request,
507 rs->request_len,
508 sa,
509 salen))
510 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
511 _("Failed to send DNS request to %s\n"),
512 GNUNET_a2s (sa,
513 salen));
514 else
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
516 _("Sent DNS request to %s\n"),
517 GNUNET_a2s (sa,
518 salen));
519 schedule_read (rs);
520}
521
522
523/**
524 * Perform DNS resolution using our default IP from init.
525 *
526 * @param ctx stub resolver to use
527 * @param request DNS request to transmit
528 * @param request_len number of bytes in msg
529 * @param rc function to call with result
530 * @param rc_cls closure for 'rc'
531 * @return socket used for the request, NULL on error
532 */
533struct GNUNET_DNSSTUB_RequestSocket *
534GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
535 const void *request,
536 size_t request_len,
537 GNUNET_DNSSTUB_ResultCallback rc,
538 void *rc_cls)
539{
540 struct GNUNET_DNSSTUB_RequestSocket *rs;
541
542 if (NULL == ctx->dns_head)
543 {
544 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545 "No DNS server configured for resolution\n");
546 return NULL;
547 }
548 if (NULL == (rs = get_request_socket (ctx)))
549 {
550 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
551 "No request socket available for DNS resolution\n");
552 return NULL;
553 }
554 rs->ds_pos = ctx->dns_head;
555 rs->rc = rc;
556 rs->rc_cls = rc_cls;
557 rs->request = GNUNET_memdup (request,
558 request_len);
559 rs->request_len = request_len;
560 rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query,
561 rs);
562 return rs;
563}
564
565
566/**
616 * Cancel DNS resolution. 567 * Cancel DNS resolution.
617 * 568 *
618 * @param rs resolution to cancel 569 * @param rs resolution to cancel
@@ -626,28 +577,153 @@ GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs)
626 GNUNET_SCHEDULER_cancel (rs->retry_task); 577 GNUNET_SCHEDULER_cancel (rs->retry_task);
627 rs->retry_task = NULL; 578 rs->retry_task = NULL;
628 } 579 }
580 if (NULL != rs->read_task)
581 {
582 GNUNET_SCHEDULER_cancel (rs->read_task);
583 rs->read_task = NULL;
584 }
629} 585}
630 586
631 587
632/** 588/**
633 * Start a DNS stub resolver. 589 * Start a DNS stub resolver.
634 * 590 *
635 * @param dns_ip target IP address to use 591 * @param num_sockets how many sockets should we open
592 * in parallel for DNS queries for this stub?
636 * @return NULL on error 593 * @return NULL on error
637 */ 594 */
638struct GNUNET_DNSSTUB_Context * 595struct GNUNET_DNSSTUB_Context *
639GNUNET_DNSSTUB_start (const char *dns_ip) 596GNUNET_DNSSTUB_start (unsigned int num_sockets)
640{ 597{
641 struct GNUNET_DNSSTUB_Context *ctx; 598 struct GNUNET_DNSSTUB_Context *ctx;
642 599
600 if (0 == num_sockets)
601 {
602 GNUNET_break (0);
603 return NULL;
604 }
643 ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context); 605 ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context);
644 if (NULL != dns_ip) 606 ctx->num_sockets = num_sockets;
645 ctx->dns_exit = GNUNET_strdup (dns_ip); 607 ctx->sockets = GNUNET_new_array (num_sockets,
608 struct GNUNET_DNSSTUB_RequestSocket);
609 ctx->retry_freq = DNS_RETRANSMIT_DELAY;
646 return ctx; 610 return ctx;
647} 611}
648 612
649 613
650/** 614/**
615 * Add nameserver for use by the DNSSTUB. We will use
616 * all provided nameservers for resolution (round-robin).
617 *
618 * @param ctx resolver context to modify
619 * @param dns_ip target IP address to use (as string)
620 * @return #GNUNET_OK on success
621 */
622int
623GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx,
624 const char *dns_ip)
625{
626 struct DnsServer *ds;
627 struct in_addr i4;
628 struct in6_addr i6;
629
630 ds = GNUNET_new (struct DnsServer);
631 if (1 == inet_pton (AF_INET,
632 dns_ip,
633 &i4))
634 {
635 struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss;
636
637 s4->sin_family = AF_INET;
638 s4->sin_port = htons (53);
639 s4->sin_addr = i4;
640#if HAVE_SOCKADDR_IN_SIN_LEN
641 s4->sin_len = (u_char) sizeof (struct sockaddr_in);
642#endif
643 }
644 else if (1 == inet_pton (AF_INET6,
645 dns_ip,
646 &i6))
647 {
648 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss;
649
650 s6->sin6_family = AF_INET6;
651 s6->sin6_port = htons (53);
652 s6->sin6_addr = i6;
653#if HAVE_SOCKADDR_IN_SIN_LEN
654 s6->sin6_len = (u_char) sizeof (struct sockaddr_in6);
655#endif
656 }
657 else
658 {
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "Malformed IP address `%s' for DNS server\n",
661 dns_ip);
662 GNUNET_free (ds);
663 return GNUNET_SYSERR;
664 }
665 GNUNET_CONTAINER_DLL_insert (ctx->dns_head,
666 ctx->dns_tail,
667 ds);
668 return GNUNET_OK;
669}
670
671
672/**
673 * Add nameserver for use by the DNSSTUB. We will use
674 * all provided nameservers for resolution (round-robin).
675 *
676 * @param ctx resolver context to modify
677 * @param sa socket address of DNS resolver to use
678 * @return #GNUNET_OK on success
679 */
680int
681GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx,
682 const struct sockaddr *sa)
683{
684 struct DnsServer *ds;
685
686 ds = GNUNET_new (struct DnsServer);
687 switch (sa->sa_family)
688 {
689 case AF_INET:
690 memcpy (&ds->ss,
691 sa,
692 sizeof (struct sockaddr_in));
693 break;
694 case AF_INET6:
695 memcpy (&ds->ss,
696 sa,
697 sizeof (struct sockaddr_in6));
698 break;
699 default:
700 GNUNET_break (0);
701 GNUNET_free (ds);
702 return GNUNET_SYSERR;
703 }
704 GNUNET_CONTAINER_DLL_insert (ctx->dns_head,
705 ctx->dns_tail,
706 ds);
707 return GNUNET_OK;
708}
709
710
711/**
712 * How long should we try requests before timing out?
713 * Only effective for requests issued after this call.
714 *
715 * @param ctx resolver context to modify
716 * @param retry_freq how long to wait between retries
717 */
718void
719GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx,
720 struct GNUNET_TIME_Relative retry_freq)
721{
722 ctx->retry_freq = retry_freq;
723}
724
725
726/**
651 * Cleanup DNSSTUB resolver. 727 * Cleanup DNSSTUB resolver.
652 * 728 *
653 * @param ctx stub resolver to clean up 729 * @param ctx stub resolver to clean up
@@ -655,15 +731,18 @@ GNUNET_DNSSTUB_start (const char *dns_ip)
655void 731void
656GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx) 732GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
657{ 733{
658 unsigned int i; 734 struct DnsServer *ds;
659 735
660 for (i=0;i<DNS_SOCKET_MAX;i++) 736 while (NULL != (ds = ctx->dns_head))
661 cleanup_rs (&ctx->sockets[i]);
662 if (NULL != ctx->dns_exit)
663 { 737 {
664 GNUNET_free (ctx->dns_exit); 738 GNUNET_CONTAINER_DLL_remove (ctx->dns_head,
665 ctx->dns_exit = NULL; 739 ctx->dns_tail,
740 ds);
741 GNUNET_free (ds);
666 } 742 }
743 for (unsigned int i=0;i<ctx->num_sockets;i++)
744 cleanup_rs (&ctx->sockets[i]);
745 GNUNET_free (ctx->sockets);
667 GNUNET_free (ctx); 746 GNUNET_free (ctx);
668} 747}
669 748
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c
index 9feaa8413..39ce7f6e5 100644
--- a/src/dns/gnunet-service-dns.c
+++ b/src/dns/gnunet-service-dns.c
@@ -508,13 +508,11 @@ send_request_to_client (struct RequestRecord *rr,
508 * succeeded. 508 * succeeded.
509 * 509 *
510 * @param cls NULL 510 * @param cls NULL
511 * @param rs the socket that received the response
512 * @param dns the response itself 511 * @param dns the response itself
513 * @param r number of bytes in dns 512 * @param r number of bytes in dns
514 */ 513 */
515static void 514static void
516process_dns_result (void *cls, 515process_dns_result (void *cls,
517 struct GNUNET_DNSSTUB_RequestSocket *rs,
518 const struct GNUNET_TUN_DnsHeader *dns, 516 const struct GNUNET_TUN_DnsHeader *dns,
519 size_t r); 517 size_t r);
520 518
@@ -530,7 +528,6 @@ next_phase (struct RequestRecord *rr)
530{ 528{
531 struct ClientRecord *cr; 529 struct ClientRecord *cr;
532 int nz; 530 int nz;
533 socklen_t salen;
534 531
535 if (rr->phase == RP_DROP) 532 if (rr->phase == RP_DROP)
536 { 533 {
@@ -582,22 +579,27 @@ next_phase (struct RequestRecord *rr)
582 next_phase (rr); 579 next_phase (rr);
583 return; 580 return;
584 case RP_QUERY: 581 case RP_QUERY:
582#if 0
583 /* TODO: optionally, use this to forward DNS requests to the
584 *original* DNS server instead of the one we have configured...
585 (but then we need to create a fresh dnsstub for each request
586 *and* manage the timeout) */
585 switch (rr->dst_addr.ss_family) 587 switch (rr->dst_addr.ss_family)
586 { 588 {
587 case AF_INET: 589 case AF_INET:
588 salen = sizeof (struct sockaddr_in); 590 salen = sizeof (struct sockaddr_in);
591 sa = (const struct sockaddr *) &rr->dst_addr;
589 break; 592 break;
590 case AF_INET6: 593 case AF_INET6:
591 salen = sizeof (struct sockaddr_in6); 594 salen = sizeof (struct sockaddr_in6);
595 sa = (const struct sockaddr *) &rr->dst_addr;
592 break; 596 break;
593 default: 597 default:
594 GNUNET_assert (0); 598 GNUNET_assert (0);
595 } 599 }
596 600#endif
597 rr->phase = RP_INTERNET_DNS; 601 rr->phase = RP_INTERNET_DNS;
598 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub, 602 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
599 (struct sockaddr*) &rr->dst_addr,
600 salen,
601 rr->payload, 603 rr->payload,
602 rr->payload_length, 604 rr->payload_length,
603 &process_dns_result, 605 &process_dns_result,
@@ -714,13 +716,11 @@ client_disconnect_cb (void *cls,
714 * succeeded. 716 * succeeded.
715 * 717 *
716 * @param cls NULL 718 * @param cls NULL
717 * @param rs the socket that received the response
718 * @param dns the response itself 719 * @param dns the response itself
719 * @param r number of bytes in dns 720 * @param r number of bytes in dns
720 */ 721 */
721static void 722static void
722process_dns_result (void *cls, 723process_dns_result (void *cls,
723 struct GNUNET_DNSSTUB_RequestSocket *rs,
724 const struct GNUNET_TUN_DnsHeader *dns, 724 const struct GNUNET_TUN_DnsHeader *dns,
725 size_t r) 725 size_t r)
726{ 726{
@@ -733,8 +733,7 @@ process_dns_result (void *cls,
733 return; /* ignore */ 733 return; /* ignore */
734 734
735 rr = &requests[dns->id]; 735 rr = &requests[dns->id];
736 if ( (rr->phase != RP_INTERNET_DNS) || 736 if (rr->phase != RP_INTERNET_DNS)
737 (rr->rs != rs) )
738 { 737 {
739 /* unexpected / bogus reply */ 738 /* unexpected / bogus reply */
740 GNUNET_STATISTICS_update (stats, 739 GNUNET_STATISTICS_update (stats,
@@ -1055,8 +1054,6 @@ run (void *cls,
1055 char *ipv4mask; 1054 char *ipv4mask;
1056 char *ipv6addr; 1055 char *ipv6addr;
1057 char *ipv6prefix; 1056 char *ipv6prefix;
1058 struct in_addr dns_exit4;
1059 struct in6_addr dns_exit6;
1060 char *dns_exit; 1057 char *dns_exit;
1061 char *binary; 1058 char *binary;
1062 int nortsetup; 1059 int nortsetup;
@@ -1065,24 +1062,26 @@ run (void *cls,
1065 stats = GNUNET_STATISTICS_create ("dns", cfg); 1062 stats = GNUNET_STATISTICS_create ("dns", cfg);
1066 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, 1063 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1067 cls); 1064 cls);
1065 dnsstub = GNUNET_DNSSTUB_start (128);
1066 /* TODO: support multiple DNS_EXIT servers being configured */
1067 /* TODO: see above TODO on using DNS server from original packet.
1068 Not sure which is best... */
1068 dns_exit = NULL; 1069 dns_exit = NULL;
1069 if ( ( (GNUNET_OK != 1070 if ( (GNUNET_OK !=
1070 GNUNET_CONFIGURATION_get_value_string (cfg, 1071 GNUNET_CONFIGURATION_get_value_string (cfg,
1071 "dns", 1072 "dns",
1072 "DNS_EXIT", 1073 "DNS_EXIT",
1073 &dns_exit)) || 1074 &dns_exit)) ||
1074 ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) && 1075 (GNUNET_OK !=
1075 (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) ) 1076 GNUNET_DNSSTUB_add_dns_ip (dnsstub,
1077 dns_exit)) )
1076 { 1078 {
1077 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 1079 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1078 "dns", 1080 "dns",
1079 "DNS_EXIT", 1081 "DNS_EXIT",
1080 _("need a valid IPv4 or IPv6 address\n")); 1082 _("need a valid IPv4 or IPv6 address\n"));
1081 GNUNET_free_non_null (dns_exit); 1083 GNUNET_free_non_null (dns_exit);
1082 dns_exit = NULL;
1083 } 1084 }
1084 dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1085 GNUNET_free_non_null (dns_exit);
1086 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns"); 1085 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
1087 if (GNUNET_YES != 1086 if (GNUNET_YES !=
1088 GNUNET_OS_check_helper_binary (binary, 1087 GNUNET_OS_check_helper_binary (binary,
diff --git a/src/dns/gnunet-zoneimport.c b/src/dns/gnunet-zoneimport.c
index 914868af4..860672e7a 100644
--- a/src/dns/gnunet-zoneimport.c
+++ b/src/dns/gnunet-zoneimport.c
@@ -290,13 +290,11 @@ process_record (struct Request *req,
290 * Function called with the result of a DNS resolution. 290 * Function called with the result of a DNS resolution.
291 * 291 *
292 * @param cls closure with the `struct Request` 292 * @param cls closure with the `struct Request`
293 * @param rs socket that received the response
294 * @param dns dns response, never NULL 293 * @param dns dns response, never NULL
295 * @param dns_len number of bytes in @a dns 294 * @param dns_len number of bytes in @a dns
296 */ 295 */
297static void 296static void
298process_result (void *cls, 297process_result (void *cls,
299 struct GNUNET_DNSSTUB_RequestSocket *rs,
300 const struct GNUNET_TUN_DnsHeader *dns, 298 const struct GNUNET_TUN_DnsHeader *dns,
301 size_t dns_len) 299 size_t dns_len)
302{ 300{
@@ -407,11 +405,11 @@ submit_req (struct Request *req)
407 (pending >= THRESH) ) 405 (pending >= THRESH) )
408 return GNUNET_SYSERR; 406 return GNUNET_SYSERR;
409 GNUNET_assert (NULL == req->rs); 407 GNUNET_assert (NULL == req->rs);
410 req->rs = GNUNET_DNSSTUB_resolve2 (ctx, 408 req->rs = GNUNET_DNSSTUB_resolve (ctx,
411 req->raw, 409 req->raw,
412 req->raw_len, 410 req->raw_len,
413 &process_result, 411 &process_result,
414 req); 412 req);
415 GNUNET_assert (NULL != req->rs); 413 GNUNET_assert (NULL != req->rs);
416 req->issue_num++; 414 req->issue_num++;
417 last_request = now; 415 last_request = now;
@@ -561,13 +559,23 @@ main (int argc,
561 "Missing required configuration argument\n"); 559 "Missing required configuration argument\n");
562 return -1; 560 return -1;
563 } 561 }
564 ctx = GNUNET_DNSSTUB_start (argv[1]); 562 ctx = GNUNET_DNSSTUB_start (256);
565 if (NULL == ctx) 563 if (NULL == ctx)
566 { 564 {
567 fprintf (stderr, 565 fprintf (stderr,
568 "Failed to initialize GNUnet DNS STUB\n"); 566 "Failed to initialize GNUnet DNS STUB\n");
569 return 1; 567 return 1;
570 } 568 }
569 if (GNUNET_OK !=
570 GNUNET_DNSSTUB_add_dns_ip (ctx,
571 argv[1]))
572 {
573 fprintf (stderr,
574 "Failed to use `%s' for DNS resolver\n",
575 argv[1]);
576 return 1;
577 }
578
571 while (NULL != 579 while (NULL !=
572 fgets (hn, 580 fgets (hn,
573 sizeof (hn), 581 sizeof (hn),
diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c
index 0b3cc505a..5cb1ebfd9 100644
--- a/src/exit/gnunet-daemon-exit.c
+++ b/src/exit/gnunet-daemon-exit.c
@@ -458,13 +458,11 @@ GNUNET_NETWORK_STRUCT_END
458 * succeeded. 458 * succeeded.
459 * 459 *
460 * @param cls NULL 460 * @param cls NULL
461 * @param rs the socket that received the response
462 * @param dns the response itself 461 * @param dns the response itself
463 * @param r number of bytes in @a dns 462 * @param r number of bytes in @a dns
464 */ 463 */
465static void 464static void
466process_dns_result (void *cls, 465process_dns_result (void *cls,
467 struct GNUNET_DNSSTUB_RequestSocket *rs,
468 const struct GNUNET_TUN_DnsHeader *dns, 466 const struct GNUNET_TUN_DnsHeader *dns,
469 size_t r) 467 size_t r)
470{ 468{
@@ -479,8 +477,7 @@ process_dns_result (void *cls,
479 return; 477 return;
480 /* Handle case that this is a reply to a request from a CADET DNS channel */ 478 /* Handle case that this is a reply to a request from a CADET DNS channel */
481 ts = channels[dns->id]; 479 ts = channels[dns->id];
482 if ( (NULL == ts) || 480 if (NULL == ts)
483 (ts->specifics.dns.rs != rs) )
484 return; 481 return;
485 LOG (GNUNET_ERROR_TYPE_DEBUG, 482 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "Got a response from the stub resolver for DNS request received via CADET!\n"); 483 "Got a response from the stub resolver for DNS request received via CADET!\n");
@@ -557,11 +554,11 @@ handle_dns_request (void *cls,
557 dlen); 554 dlen);
558 dout = (struct GNUNET_TUN_DnsHeader *) buf; 555 dout = (struct GNUNET_TUN_DnsHeader *) buf;
559 dout->id = ts->specifics.dns.my_id; 556 dout->id = ts->specifics.dns.my_id;
560 ts->specifics.dns.rs = GNUNET_DNSSTUB_resolve2 (dnsstub, 557 ts->specifics.dns.rs = GNUNET_DNSSTUB_resolve (dnsstub,
561 buf, 558 buf,
562 dlen, 559 dlen,
563 &process_dns_result, 560 &process_dns_result,
564 NULL); 561 NULL);
565 if (NULL == ts->specifics.dns.rs) 562 if (NULL == ts->specifics.dns.rs)
566 { 563 {
567 GNUNET_break_op (0); 564 GNUNET_break_op (0);
@@ -3545,25 +3542,23 @@ advertise_dns_exit ()
3545 }; 3542 };
3546 char *dns_exit; 3543 char *dns_exit;
3547 struct GNUNET_HashCode port; 3544 struct GNUNET_HashCode port;
3548 struct in_addr dns_exit4;
3549 struct in6_addr dns_exit6;
3550 3545
3551 if (GNUNET_YES != 3546 if (GNUNET_YES !=
3552 GNUNET_CONFIGURATION_get_value_yesno (cfg, 3547 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3553 "exit", 3548 "exit",
3554 "EXIT_DNS")) 3549 "EXIT_DNS"))
3555 return; 3550 return;
3551 GNUNET_assert (NULL != (dnsstub = GNUNET_DNSSTUB_start (128)));
3552 dns_exit = NULL;
3553 /* TODO: support using multiple DNS resolvers */
3556 if ( (GNUNET_OK != 3554 if ( (GNUNET_OK !=
3557 GNUNET_CONFIGURATION_get_value_string (cfg, 3555 GNUNET_CONFIGURATION_get_value_string (cfg,
3558 "exit", 3556 "exit",
3559 "DNS_RESOLVER", 3557 "DNS_RESOLVER",
3560 &dns_exit)) || 3558 &dns_exit)) ||
3561 ( (1 != inet_pton (AF_INET, 3559 (GNUNET_OK !=
3562 dns_exit, 3560 GNUNET_DNSSTUB_add_dns_ip (dnsstub,
3563 &dns_exit4)) && 3561 dns_exit)) )
3564 (1 != inet_pton (AF_INET6,
3565 dns_exit,
3566 &dns_exit6)) ) )
3567 { 3562 {
3568 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 3563 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3569 "dns", 3564 "dns",
diff --git a/src/gns/gnunet-dns2gns.c b/src/gns/gnunet-dns2gns.c
index 47cc6dde0..bc66f1325 100644
--- a/src/gns/gnunet-dns2gns.c
+++ b/src/gns/gnunet-dns2gns.c
@@ -247,19 +247,16 @@ do_timeout (void *cls)
247 * Iterator called on obtained result for a DNS lookup 247 * Iterator called on obtained result for a DNS lookup
248 * 248 *
249 * @param cls closure 249 * @param cls closure
250 * @param rs the request socket
251 * @param dns the DNS udp payload 250 * @param dns the DNS udp payload
252 * @param r size of the DNS payload 251 * @param r size of the DNS payload
253 */ 252 */
254static void 253static void
255dns_result_processor (void *cls, 254dns_result_processor (void *cls,
256 struct GNUNET_DNSSTUB_RequestSocket *rs,
257 const struct GNUNET_TUN_DnsHeader *dns, 255 const struct GNUNET_TUN_DnsHeader *dns,
258 size_t r) 256 size_t r)
259{ 257{
260 struct Request *request = cls; 258 struct Request *request = cls;
261 259
262 (void) rs;
263 if (NULL == dns) 260 if (NULL == dns)
264 { 261 {
265 /* DNSSTUB gave up, so we trigger timeout early */ 262 /* DNSSTUB gave up, so we trigger timeout early */
@@ -307,11 +304,11 @@ result_processor (void *cls,
307 request->original_request_id = request->packet->id; 304 request->original_request_id = request->packet->id;
308 GNUNET_DNSPARSER_free_packet (request->packet); 305 GNUNET_DNSPARSER_free_packet (request->packet);
309 request->packet = NULL; 306 request->packet = NULL;
310 request->dns_lookup = GNUNET_DNSSTUB_resolve2 (dns_stub, 307 request->dns_lookup = GNUNET_DNSSTUB_resolve (dns_stub,
311 request->udp_msg, 308 request->udp_msg,
312 request->udp_msg_size, 309 request->udp_msg_size,
313 &dns_result_processor, 310 &dns_result_processor,
314 request); 311 request);
315 return; 312 return;
316 } 313 }
317 packet = request->packet; 314 packet = request->packet;
@@ -594,8 +591,12 @@ run (void *cls,
594 NULL); 591 NULL);
595 if (NULL == (gns = GNUNET_GNS_connect (cfg))) 592 if (NULL == (gns = GNUNET_GNS_connect (cfg)))
596 return; 593 return;
597 if (NULL == (dns_stub = GNUNET_DNSSTUB_start (dns_ip))) 594 GNUNET_assert (NULL != (dns_stub = GNUNET_DNSSTUB_start (128)));
595 if (GNUNET_OK !=
596 GNUNET_DNSSTUB_add_dns_ip (dns_stub,
597 dns_ip))
598 { 598 {
599 GNUNET_DNSSTUB_stop (dns_stub);
599 GNUNET_GNS_disconnect (gns); 600 GNUNET_GNS_disconnect (gns);
600 gns = NULL; 601 gns = NULL;
601 return; 602 return;
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
index 94819b040..74eb47f29 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -72,6 +72,57 @@
72 * DLL to hold the authority chain we had to pass in the resolution 72 * DLL to hold the authority chain we had to pass in the resolution
73 * process. 73 * process.
74 */ 74 */
75struct AuthorityChain;
76
77
78/**
79 * Element of a resolution process for looking up the
80 * responsible DNS server hostname in a GNS2DNS recursive
81 * resolution.
82 */
83struct Gns2DnsPending
84{
85
86 /**
87 * Kept in a DLL.
88 */
89 struct Gns2DnsPending *next;
90
91 /**
92 * Kept in a DLL.
93 */
94 struct Gns2DnsPending *prev;
95
96 /**
97 * Context this activity belongs with.
98 */
99 struct AuthorityChain *ac;
100
101 /**
102 * Handle for the resolution of the IP part of the
103 * GNS2DNS record. Will return to us the addresses
104 * of the DNS resolver to use.
105 */
106 struct GNS_ResolverHandle *rh;
107
108 /**
109 * Handle for DNS resolution of the DNS nameserver.
110 */
111 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
112};
113
114
115/**
116 * Handle to a currenty pending resolution. On result (positive or
117 * negative) the #GNS_ResultProcessor is called.
118 */
119struct GNS_ResolverHandle;
120
121
122/**
123 * DLL to hold the authority chain we had to pass in the resolution
124 * process.
125 */
75struct AuthorityChain 126struct AuthorityChain
76{ 127{
77 /** 128 /**
@@ -131,11 +182,32 @@ struct AuthorityChain
131 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1]; 182 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
132 183
133 /** 184 /**
134 * IP address of the DNS resolver that is authoritative. 185 * List of resolutions of the 'ip' of the name server that
135 * (this implementation currently only supports one 186 * are still pending.
136 * IP at a time). 187 */
188 struct Gns2DnsPending *gp_head;
189
190 /**
191 * Tail of list of resolutions of the 'ip' of the name server that
192 * are still pending.
193 */
194 struct Gns2DnsPending *gp_tail;
195
196 /**
197 * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
198 */
199 struct GNUNET_DNSSTUB_Context *dns_handle;
200
201 /**
202 * Did we succeed in getting an IP address for *any* of the DNS servers listed?
203 * Once we do, we can start with DNS queries.
204 */
205 int found;
206
207 /**
208 * Did we start the recursive resolution via DNS?
137 */ 209 */
138 struct sockaddr_storage dns_ip; 210 int launched;
139 211
140 } dns_authority; 212 } dns_authority;
141 213
@@ -218,34 +290,6 @@ struct VpnContext
218 290
219 291
220/** 292/**
221 * Information we keep during the resolution of an
222 * IP address for a DNS server while handling a
223 * GNS2DNS record.
224 */
225struct Gns2DnsContext
226{
227
228 /**
229 * DNS domain in which the resolution will continue
230 * (first part of the GNS2DNS record).
231 */
232 char *ns;
233
234 /**
235 * Handle for the resolution of the IP part of the
236 * GNS2DNS record. Will return to us the addresses
237 * of the DNS resolver to use.
238 */
239 struct GNS_ResolverHandle *rh;
240
241 /**
242 * Handle for DNS resolution of the DNS nameserver.
243 */
244 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
245};
246
247
248/**
249 * Handle to a currenty pending resolution. On result (positive or 293 * Handle to a currenty pending resolution. On result (positive or
250 * negative) the #GNS_ResultProcessor is called. 294 * negative) the #GNS_ResultProcessor is called.
251 */ 295 */
@@ -278,12 +322,6 @@ struct GNS_ResolverHandle
278 void* proc_cls; 322 void* proc_cls;
279 323
280 /** 324 /**
281 * Handle used during GNS2DNS resolution for looking up the
282 * IP address of the DNS server.
283 */
284 struct Gns2DnsContext *g2dc;
285
286 /**
287 * Handle for DHT lookups. should be NULL if no lookups are in progress 325 * Handle for DHT lookups. should be NULL if no lookups are in progress
288 */ 326 */
289 struct GNUNET_DHT_GetHandle *get_handle; 327 struct GNUNET_DHT_GetHandle *get_handle;
@@ -431,11 +469,6 @@ static struct GNUNET_VPN_Handle *vpn_handle;
431static struct GNUNET_DHT_Handle *dht_handle; 469static struct GNUNET_DHT_Handle *dht_handle;
432 470
433/** 471/**
434 * Handle to perform DNS lookups.
435 */
436static struct GNUNET_DNSSTUB_Context *dns_handle;
437
438/**
439 * Heap for limiting parallel DHT lookups 472 * Heap for limiting parallel DHT lookups
440 */ 473 */
441static struct GNUNET_CONTAINER_Heap *dht_lookup_heap; 474static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
@@ -543,21 +576,53 @@ translate_dot_plus (struct GNS_ResolverHandle *rh,
543 576
544 577
545/** 578/**
546 * Task scheduled to asynchronously fail a resolution. 579 * Wrapper around #GNS_resolver_lookup_cancel() as a task.
580 * Used for delayed cleanup so we can unwind the stack first.
547 * 581 *
548 * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail 582 * @param cls the `struct GNS_ResolverHandle`
549 */ 583 */
550static void 584static void
551fail_resolution (void *cls) 585GNS_resolver_lookup_cancel_ (void *cls)
552{ 586{
553 struct GNS_ResolverHandle *rh = cls; 587 struct GNS_ResolverHandle *rh = cls;
554 588
555 rh->task_id = NULL; 589 rh->task_id = NULL;
556 rh->proc (rh->proc_cls, 0, NULL);
557 GNS_resolver_lookup_cancel (rh); 590 GNS_resolver_lookup_cancel (rh);
558} 591}
559 592
560 593
594/**
595 * Function called to asynchronously fail a resolution.
596 *
597 * @param rh the resolution to fail
598 */
599static void
600fail_resolution (struct GNS_ResolverHandle *rh)
601{
602 rh->proc (rh->proc_cls,
603 0,
604 NULL);
605 GNUNET_assert (NULL == rh->task_id);
606 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
607 rh);
608}
609
610
611/**
612 * Function called when a resolution times out.
613 *
614 * @param cls the `struct GNS_ResolverHandle`
615 */
616static void
617timeout_resolution (void *cls)
618{
619 struct GNS_ResolverHandle *rh = cls;
620
621 rh->task_id = NULL;
622 fail_resolution (rh);
623}
624
625
561#if (defined WINDOWS) || (defined DARWIN) 626#if (defined WINDOWS) || (defined DARWIN)
562/* Don't have this on W32, here's a naive implementation 627/* Don't have this on W32, here's a naive implementation
563 * Was somehow removed on OS X ... */ 628 * Was somehow removed on OS X ... */
@@ -831,13 +896,11 @@ start_resolver_lookup (void *cls);
831 * 896 *
832 * @param cls the request handle of the resolution that 897 * @param cls the request handle of the resolution that
833 * we were attempting to make 898 * we were attempting to make
834 * @param rs socket that received the response
835 * @param dns dns response, never NULL 899 * @param dns dns response, never NULL
836 * @param dns_len number of bytes in @a dns 900 * @param dns_len number of bytes in @a dns
837 */ 901 */
838static void 902static void
839dns_result_parser (void *cls, 903dns_result_parser (void *cls,
840 struct GNUNET_DNSSTUB_RequestSocket *rs,
841 const struct GNUNET_TUN_DnsHeader *dns, 904 const struct GNUNET_TUN_DnsHeader *dns,
842 size_t dns_len) 905 size_t dns_len)
843{ 906{
@@ -845,18 +908,13 @@ dns_result_parser (void *cls,
845 struct GNUNET_DNSPARSER_Packet *p; 908 struct GNUNET_DNSPARSER_Packet *p;
846 const struct GNUNET_DNSPARSER_Record *rec; 909 const struct GNUNET_DNSPARSER_Record *rec;
847 unsigned int rd_count; 910 unsigned int rd_count;
848 unsigned int i;
849 911
850 (void) rs;
851 if (NULL == dns) 912 if (NULL == dns)
852 { 913 {
853 rh->dns_request = NULL; 914 rh->dns_request = NULL;
854 GNUNET_SCHEDULER_cancel (rh->task_id); 915 GNUNET_SCHEDULER_cancel (rh->task_id);
855 rh->task_id = NULL; 916 rh->task_id = NULL;
856 rh->proc (rh->proc_cls, 917 fail_resolution (rh);
857 0,
858 NULL);
859 GNS_resolver_lookup_cancel (rh);
860 return; 918 return;
861 } 919 }
862 if (rh->original_dns_id != dns->id) 920 if (rh->original_dns_id != dns->id)
@@ -872,6 +930,8 @@ dns_result_parser (void *cls,
872 _("Failed to parse DNS response\n")); 930 _("Failed to parse DNS response\n"));
873 return; 931 return;
874 } 932 }
933
934 /* We got a result from DNS */
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876 "Received DNS response for `%s' with %u answers\n", 936 "Received DNS response for `%s' with %u answers\n",
877 rh->ac_tail->label, 937 rh->ac_tail->label,
@@ -920,8 +980,10 @@ dns_result_parser (void *cls,
920 980
921 buf_off = 0; 981 buf_off = 0;
922 skip = 0; 982 skip = 0;
923 memset (rd, 0, sizeof (rd)); 983 memset (rd,
924 for (i=0;i<rd_count;i++) 984 0,
985 sizeof (rd));
986 for (unsigned int i=0;i<rd_count;i++)
925 { 987 {
926 if (i < p->num_answers) 988 if (i < p->num_answers)
927 rec = &p->answers[i]; 989 rec = &p->answers[i];
@@ -1043,9 +1105,12 @@ dns_result_parser (void *cls,
1043 rh->proc (rh->proc_cls, 1105 rh->proc (rh->proc_cls,
1044 rd_count - skip, 1106 rd_count - skip,
1045 rd); 1107 rd);
1046 GNS_resolver_lookup_cancel (rh);
1047 } 1108 }
1048 GNUNET_DNSPARSER_free_packet (p); 1109 GNUNET_DNSPARSER_free_packet (p);
1110 if (NULL != rh->task_id)
1111 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1112 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1113 rh);
1049} 1114}
1050 1115
1051 1116
@@ -1061,7 +1126,6 @@ static void
1061recursive_dns_resolution (struct GNS_ResolverHandle *rh) 1126recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1062{ 1127{
1063 struct AuthorityChain *ac; 1128 struct AuthorityChain *ac;
1064 socklen_t sa_len;
1065 struct GNUNET_DNSPARSER_Query *query; 1129 struct GNUNET_DNSPARSER_Query *query;
1066 struct GNUNET_DNSPARSER_Packet *p; 1130 struct GNUNET_DNSPARSER_Packet *p;
1067 char *dns_request; 1131 char *dns_request;
@@ -1074,20 +1138,6 @@ recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1074 "Starting DNS lookup for `%s'\n", 1138 "Starting DNS lookup for `%s'\n",
1075 ac->label); 1139 ac->label);
1076 GNUNET_assert (GNUNET_NO == ac->gns_authority); 1140 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1077 switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
1078 {
1079 case AF_INET:
1080 sa_len = sizeof (struct sockaddr_in);
1081 break;
1082 case AF_INET6:
1083 sa_len = sizeof (struct sockaddr_in6);
1084 break;
1085 default:
1086 GNUNET_break (0);
1087 rh->proc (rh->proc_cls, 0, NULL);
1088 GNS_resolver_lookup_cancel (rh);
1089 return;
1090 }
1091 query = GNUNET_new (struct GNUNET_DNSPARSER_Query); 1141 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1092 query->name = GNUNET_strdup (ac->label); 1142 query->name = GNUNET_strdup (ac->label);
1093 query->type = rh->record_type; 1143 query->type = rh->record_type;
@@ -1109,20 +1159,22 @@ recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1109 rh->proc (rh->proc_cls, 1159 rh->proc (rh->proc_cls,
1110 0, 1160 0,
1111 NULL); 1161 NULL);
1112 GNS_resolver_lookup_cancel (rh); 1162 GNUNET_assert (NULL == rh->task_id);
1163 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1164 rh);
1113 } 1165 }
1114 else 1166 else
1115 { 1167 {
1116 rh->original_dns_id = p->id; 1168 rh->original_dns_id = p->id;
1117 rh->dns_request = GNUNET_DNSSTUB_resolve (dns_handle, 1169 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1118 (const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip, 1170 GNUNET_assert (NULL == rh->dns_request);
1119 sa_len, 1171 rh->dns_request = GNUNET_DNSSTUB_resolve (ac->authority_info.dns_authority.dns_handle,
1120 dns_request, 1172 dns_request,
1121 dns_request_length, 1173 dns_request_length,
1122 &dns_result_parser, 1174 &dns_result_parser,
1123 rh); 1175 rh);
1124 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT, 1176 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1125 &fail_resolution, 1177 &timeout_resolution,
1126 rh); 1178 rh);
1127 } 1179 }
1128 if (GNUNET_SYSERR != ret) 1180 if (GNUNET_SYSERR != ret)
@@ -1293,15 +1345,47 @@ vpn_allocation_cb (void *cls,
1293 1345
1294 1346
1295/** 1347/**
1348 * We have resolved one or more of the nameservers for a
1349 * GNS2DNS lookup. Once we have some of them, begin using
1350 * the DNSSTUB resolver.
1351 *
1352 * @param ac context for GNS2DNS resolution
1353 */
1354static void
1355continue_with_gns2dns (struct AuthorityChain *ac)
1356{
1357 struct GNS_ResolverHandle *rh = ac->rh;
1358
1359 if ( (NULL != ac->authority_info.dns_authority.gp_head) &&
1360 (GNUNET_NO == ac->authority_info.dns_authority.found) )
1361 return; /* more pending and none found yet */
1362 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1363 {
1364 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1365 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1366 ac->authority_info.dns_authority.name);
1367 fail_resolution (rh);
1368 return;
1369 }
1370 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1371 return; /* already running, do not launch again! */
1372 /* recurse */
1373 ac->authority_info.dns_authority.launched = GNUNET_YES;
1374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1375 "Will continue resolution using DNS to resolve `%s'\n",
1376 ac->label);
1377 GNUNET_assert (NULL == rh->task_id);
1378 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1379 rh);
1380
1381}
1382
1383
1384/**
1296 * We've resolved the IP address for the DNS resolver to use 1385 * We've resolved the IP address for the DNS resolver to use
1297 * after encountering a GNS2DNS record. 1386 * after encountering a GNS2DNS record.
1298 * 1387 *
1299 * TODO: Right now we only foward the request to ONE DNS resolver, 1388 * @param cls the `struct Gns2DnsPending` used for this request
1300 * even if we get multiple IP addresses back; a correct implementation
1301 * should try all DNS resolvers.
1302 *
1303 * @param cls the `struct GNS_ResolverHandle` where we encountered
1304 * the GNS2DNS record
1305 * @param rd_count number of records in @a rd 1389 * @param rd_count number of records in @a rd
1306 * @param rd addresses for the DNS resolver (presumably) 1390 * @param rd addresses for the DNS resolver (presumably)
1307 */ 1391 */
@@ -1310,136 +1394,96 @@ handle_gns2dns_result (void *cls,
1310 unsigned int rd_count, 1394 unsigned int rd_count,
1311 const struct GNUNET_GNSRECORD_Data *rd) 1395 const struct GNUNET_GNSRECORD_Data *rd)
1312{ 1396{
1313 struct GNS_ResolverHandle *rh = cls; 1397 struct Gns2DnsPending *gp = cls;
1314 struct AuthorityChain *ac; 1398 struct AuthorityChain *ac = gp->ac;
1315 struct sockaddr *sa; 1399
1316 struct sockaddr_in v4; 1400 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1317 struct sockaddr_in6 v6; 1401 ac->authority_info.dns_authority.gp_tail,
1318 size_t sa_len; 1402 gp);
1319 1403 /* enable cleanup of 'rh' handle that automatically comes after we return,
1320 /* find suitable A/AAAA record */ 1404 and which expects 'rh' to be in the #rlh_head DLL. */
1321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1405 if (NULL != gp->rh)
1322 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1323 rd_count);
1324 /* enable cleanup of 'rh' handle that comes next... */
1325 if (NULL != rh->g2dc->rh)
1326 { 1406 {
1327 GNUNET_CONTAINER_DLL_insert (rlh_head, 1407 GNUNET_CONTAINER_DLL_insert (rlh_head,
1328 rlh_tail, 1408 rlh_tail,
1329 rh->g2dc->rh); 1409 gp->rh);
1330 rh->g2dc->rh = NULL; 1410 gp->rh = NULL;
1331 } 1411 }
1332 sa = NULL; 1412 GNUNET_free (gp);
1333 sa_len = 0; 1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1415 rd_count);
1416 /* find suitable A/AAAA record */
1334 for (unsigned int j=0;j<rd_count;j++) 1417 for (unsigned int j=0;j<rd_count;j++)
1335 { 1418 {
1336 switch (rd[j].record_type) 1419 switch (rd[j].record_type)
1337 { 1420 {
1338 case GNUNET_DNSPARSER_TYPE_A: 1421 case GNUNET_DNSPARSER_TYPE_A:
1339 if (sizeof (struct in_addr) != rd[j].data_size)
1340 { 1422 {
1341 GNUNET_break_op (0); 1423 struct sockaddr_in v4;
1342 rh->proc (rh->proc_cls, 0, NULL); 1424
1343 GNS_resolver_lookup_cancel (rh); 1425 if (sizeof (struct in_addr) != rd[j].data_size)
1344 return; 1426 {
1345 } 1427 GNUNET_break_op (0);
1346 /* FIXME: might want to check if we support IPv4 here, 1428 continue;
1347 and otherwise skip this one and hope we find another */ 1429 }
1348 memset (&v4, 0, sizeof (v4)); 1430 memset (&v4,
1349 sa_len = sizeof (v4); 1431 0,
1350 v4.sin_family = AF_INET; 1432 sizeof (v4));
1351 v4.sin_port = htons (53); 1433 v4.sin_family = AF_INET;
1434 v4.sin_port = htons (53);
1352#if HAVE_SOCKADDR_IN_SIN_LEN 1435#if HAVE_SOCKADDR_IN_SIN_LEN
1353 v4.sin_len = (u_char) sa_len; 1436 v4.sin_len = (u_char) sizeof (v4);
1354#endif 1437#endif
1355 GNUNET_memcpy (&v4.sin_addr, 1438 GNUNET_memcpy (&v4.sin_addr,
1356 rd[j].data, 1439 rd[j].data,
1357 sizeof (struct in_addr)); 1440 sizeof (struct in_addr));
1358 sa = (struct sockaddr *) &v4; 1441 if (GNUNET_OK ==
1359 break; 1442 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1443 (const struct sockaddr *) &v4))
1444 ac->authority_info.dns_authority.found = GNUNET_YES;
1445 break;
1446 }
1360 case GNUNET_DNSPARSER_TYPE_AAAA: 1447 case GNUNET_DNSPARSER_TYPE_AAAA:
1361 if (sizeof (struct in6_addr) != rd[j].data_size)
1362 { 1448 {
1363 GNUNET_break_op (0); 1449 struct sockaddr_in6 v6;
1364 rh->proc (rh->proc_cls, 0, NULL); 1450
1365 GNS_resolver_lookup_cancel (rh); 1451 if (sizeof (struct in6_addr) != rd[j].data_size)
1366 return; 1452 {
1367 } 1453 GNUNET_break_op (0);
1368 /* FIXME: might want to check if we support IPv6 here, 1454 continue;
1369 and otherwise skip this one and hope we find another */ 1455 }
1370 memset (&v6, 0, sizeof (v6)); 1456 /* FIXME: might want to check if we support IPv6 here,
1371 sa_len = sizeof (v6); 1457 and otherwise skip this one and hope we find another */
1372 v6.sin6_family = AF_INET6; 1458 memset (&v6,
1373 v6.sin6_port = htons (53); 1459 0,
1460 sizeof (v6));
1461 v6.sin6_family = AF_INET6;
1462 v6.sin6_port = htons (53);
1374#if HAVE_SOCKADDR_IN_SIN_LEN 1463#if HAVE_SOCKADDR_IN_SIN_LEN
1375 v6.sin6_len = (u_char) sa_len; 1464 v6.sin6_len = (u_char) sizeof (v6);
1376#endif 1465#endif
1377 GNUNET_memcpy (&v6.sin6_addr, 1466 GNUNET_memcpy (&v6.sin6_addr,
1378 rd[j].data, 1467 rd[j].data,
1379 sizeof (struct in6_addr)); 1468 sizeof (struct in6_addr));
1380 sa = (struct sockaddr *) &v6; 1469 if (GNUNET_OK ==
1381 break; 1470 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1471 (const struct sockaddr *) &v6))
1472 ac->authority_info.dns_authority.found = GNUNET_YES;
1473 break;
1474 }
1382 default: 1475 default:
1383 break; 1476 break;
1384 } 1477 }
1385 if (NULL != sa)
1386 break;
1387 }
1388 if (NULL == sa)
1389 {
1390 /* we cannot continue; NS without A/AAAA */
1391 rh->proc (rh->proc_cls, 0, NULL);
1392 GNS_resolver_lookup_cancel (rh);
1393 return;
1394 }
1395 /* expand authority chain */
1396 ac = GNUNET_new (struct AuthorityChain);
1397 ac->rh = rh;
1398 GNUNET_assert (strlen (rh->g2dc->ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1399 strcpy (ac->authority_info.dns_authority.name,
1400 rh->g2dc->ns);
1401 GNUNET_memcpy (&ac->authority_info.dns_authority.dns_ip,
1402 sa,
1403 sa_len);
1404 /* for DNS recursion, the label is the full DNS name,
1405 created from the remainder of the GNS name and the
1406 name in the NS record */
1407 GNUNET_asprintf (&ac->label,
1408 "%.*s%s%s",
1409 (int) rh->name_resolution_pos,
1410 rh->name,
1411 (0 != rh->name_resolution_pos) ? "." : "",
1412 rh->g2dc->ns);
1413 GNUNET_free (rh->g2dc->ns);
1414 GNUNET_free (rh->g2dc);
1415 rh->g2dc = NULL;
1416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1417 "Will continue resolution using DNS server `%s' to resolve `%s'\n",
1418 GNUNET_a2s (sa,
1419 sa_len),
1420 ac->label);
1421 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1422 rh->ac_tail,
1423 ac);
1424 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1425 {
1426 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1427 _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1428 ac->label);
1429 rh->proc (rh->proc_cls, 0, NULL);
1430 GNS_resolver_lookup_cancel (rh);
1431 return;
1432 } 1478 }
1433 /* recurse */ 1479 continue_with_gns2dns (ac);
1434 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1435 rh);
1436} 1480}
1437 1481
1438 1482
1439/** 1483/**
1440 * Function called by the resolver for each address obtained from DNS. 1484 * Function called by the resolver for each address obtained from DNS.
1441 * 1485 *
1442 * @param cls closure, a `struct Gns2DnsContext *` 1486 * @param cls closure, a `struct Gns2DnsPending *`
1443 * @param addr one of the addresses of the host, NULL for the last address 1487 * @param addr one of the addresses of the host, NULL for the last address
1444 * @param addrlen length of @a addr 1488 * @param addrlen length of @a addr
1445 */ 1489 */
@@ -1448,57 +1492,270 @@ handle_gns2dns_ip (void *cls,
1448 const struct sockaddr *addr, 1492 const struct sockaddr *addr,
1449 socklen_t addrlen) 1493 socklen_t addrlen)
1450{ 1494{
1451 struct Gns2DnsContext *g2dc = cls; 1495 struct Gns2DnsPending *gp = cls;
1452 struct GNUNET_GNSRECORD_Data rd; 1496 struct AuthorityChain *ac = gp->ac;
1453 1497
1498 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
1499 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1500 ac->authority_info.dns_authority.gp_tail,
1501 gp);
1502 GNUNET_free (gp);
1454 if (NULL == addr) 1503 if (NULL == addr)
1455 { 1504 {
1456 /* DNS resolution failed */ 1505 /* DNS resolution failed */
1457 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1506 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1458 "Failed to use DNS to resolve name of DNS resolver\n"); 1507 "Failed to use DNS to resolve name of DNS resolver\n");
1459 g2dc->rh->g2dc = NULL;
1460 fail_resolution (g2dc->rh);
1461 GNUNET_free (g2dc);
1462 } 1508 }
1463 switch (addr->sa_family) 1509 else
1464 { 1510 {
1465 case AF_INET: 1511 if (GNUNET_OK ==
1512 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1513 addr))
1514 ac->authority_info.dns_authority.found = GNUNET_YES;
1515 }
1516 continue_with_gns2dns (ac);
1517}
1518
1519
1520/**
1521 * We found a CNAME record, perform recursive resolution on it.
1522 *
1523 * @param rh resolution handle
1524 * @param rd record with CNAME to resolve recursively
1525 */
1526static void
1527recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1528 const struct GNUNET_GNSRECORD_Data *rd)
1529{
1530 char *cname;
1531 size_t off;
1532
1533 off = 0;
1534 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1535 rd->data_size,
1536 &off);
1537 if ( (NULL == cname) ||
1538 (off != rd->data_size) )
1539 {
1540 GNUNET_break_op (0); /* record not well-formed */
1541 GNUNET_free_non_null (cname);
1542 fail_resolution (rh);
1543 return;
1544 }
1545 handle_gns_cname_result (rh,
1546 cname);
1547 GNUNET_free (cname);
1548}
1549
1550
1551/**
1552 * We found a PKEY record, perform recursive resolution on it.
1553 *
1554 * @param rh resolution handle
1555 * @param rd record with PKEY to resolve recursively
1556 */
1557static void
1558recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1559 const struct GNUNET_GNSRECORD_Data *rd)
1560{
1561 struct AuthorityChain *ac;
1562
1563 /* delegation to another zone */
1564 if (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) !=
1565 rd->data_size)
1566 {
1567 GNUNET_break_op (0);
1568 fail_resolution (rh);
1569 return;
1570 }
1571 /* expand authority chain */
1572 ac = GNUNET_new (struct AuthorityChain);
1573 ac->rh = rh;
1574 ac->gns_authority = GNUNET_YES;
1575 ac->suggested_shortening_label = NULL;
1576 ac->shortening_started = GNUNET_NO;
1577 GNUNET_memcpy (&ac->authority_info.gns_authority,
1578 rd->data,
1579 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1580 ac->label = resolver_lookup_get_next_label (rh);
1581 /* add AC to tail */
1582 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1583 rh->ac_tail,
1584 ac);
1585 /* recurse */
1586 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1587 rh);
1588}
1589
1590
1591/**
1592 * We found one or more GNS2DNS records, perform recursive resolution on it.
1593 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1594 * so this function still needs to check which ones are GNS2DNS).
1595 *
1596 * @param rh resolution handle
1597 * @param rd_count length of the @a rd array
1598 * @param rd record with PKEY to resolve recursively
1599 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1600 */
1601static int
1602recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1603 unsigned int rd_count,
1604 const struct GNUNET_GNSRECORD_Data *rd)
1605{
1606 struct AuthorityChain *ac;
1607 const char *tld;
1608 char *ns;
1609
1610 ns = NULL;
1611 /* expand authority chain */
1612 ac = GNUNET_new (struct AuthorityChain);
1613 ac->rh = rh;
1614 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1615
1616 for (unsigned int i=0;i<rd_count;i++)
1617 {
1618 char *ip;
1619 char *n;
1620 size_t off;
1621 struct Gns2DnsPending *gp;
1622 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1623
1624 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1625 continue;
1626 off = 0;
1627 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1628 rd[i].data_size,
1629 &off);
1630 ip = GNUNET_DNSPARSER_parse_name (rd[i].data,
1631 rd[i].data_size,
1632 &off);
1633 if ( (NULL == n) ||
1634 (NULL == ip) ||
1635 (off != rd[i].data_size) )
1466 { 1636 {
1467 const struct sockaddr_in *v4 = (const struct sockaddr_in *) addr; 1637 GNUNET_break_op (0);
1468 1638 GNUNET_free_non_null (n);
1469 GNUNET_assert (sizeof (*v4) == addrlen); 1639 GNUNET_free_non_null (ip);
1470 rd.data = v4; 1640 continue;
1471 rd.data_size = sizeof (*v4);
1472 rd.expiration_time = UINT64_MAX;
1473 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
1474 rd.flags = 0;
1475 break;
1476 } 1641 }
1477 case AF_INET6: 1642 /* resolve 'ip' to determine the IP(s) of the DNS
1643 resolver to use for lookup of 'ns' */
1644 if (NULL != ns)
1478 { 1645 {
1479 const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *) addr; 1646 if (0 != strcasecmp (ns,
1480 1647 n))
1481 GNUNET_assert (sizeof (*v6) == addrlen); 1648 {
1482 rd.data = v6; 1649 /* NS values must all be the same for all GNS2DNS records,
1483 rd.data_size = sizeof (v6); 1650 anything else leads to insanity */
1484 rd.expiration_time = UINT64_MAX; 1651 GNUNET_break_op (0);
1485 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA; 1652 GNUNET_free (n);
1486 rd.flags = 0; 1653 GNUNET_free (ip);
1487 break; 1654 continue;
1655 }
1656 GNUNET_free (n);
1657 }
1658 else
1659 {
1660 ns = n;
1488 } 1661 }
1489 default:
1490 return;
1491 }
1492 GNUNET_RESOLVER_request_cancel (g2dc->dns_rh);
1493 g2dc->dns_rh = NULL;
1494 handle_gns2dns_result (g2dc->rh,
1495 1,
1496 &rd);
1497 1662
1663 /* check if 'ip' is already an IPv4/IPv6 address */
1664 if (GNUNET_OK ==
1665 GNUNET_DNSSTUB_add_dns_ip (ac->authority_info.dns_authority.dns_handle,
1666 ip))
1667 {
1668 ac->authority_info.dns_authority.found = GNUNET_YES;
1669 GNUNET_free (ip);
1670 continue;
1671 }
1672 tld = GNS_get_tld (ip);
1673 if (0 != strcmp (tld,
1674 "+"))
1675 {
1676 /* 'ip' is a DNS name */
1677 gp = GNUNET_new (struct Gns2DnsPending);
1678 gp->ac = ac;
1679 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1680 ac->authority_info.dns_authority.gp_tail,
1681 gp);
1682 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1683 AF_UNSPEC,
1684 GNUNET_TIME_UNIT_FOREVER_REL,
1685 &handle_gns2dns_ip,
1686 gp);
1687 GNUNET_free (ip);
1688 continue;
1689 }
1690 /* 'ip' should be a GNS name */
1691 gp = GNUNET_new (struct Gns2DnsPending);
1692 gp->ac = ac;
1693 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1694 ac->authority_info.dns_authority.gp_tail,
1695 gp);
1696 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1697 ip = translate_dot_plus (rh,
1698 ip);
1699 tld = GNS_get_tld (ip);
1700 if (GNUNET_OK !=
1701 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1702 &zone))
1703 {
1704 GNUNET_break_op (0);
1705 GNUNET_free (ip);
1706 continue;
1707 }
1708 gp->rh->authority_zone = zone;
1709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1710 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1711 ip,
1712 ns);
1713 gp->rh->name = ip;
1714 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1715 gp->rh->proc = &handle_gns2dns_result;
1716 gp->rh->proc_cls = gp;
1717 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1718 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1719 gp->rh->loop_limiter = rh->loop_limiter + 1;
1720 gp->rh->task_id
1721 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1722 gp->rh);
1723 } /* end 'for all records' */
1724
1725 if (NULL == ns)
1726 {
1727 /* not a single GNS2DNS record found */
1728 GNUNET_free (ac);
1729 return GNUNET_SYSERR;
1730 }
1731 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1732 strcpy (ac->authority_info.dns_authority.name,
1733 ns);
1734 /* for DNS recursion, the label is the full DNS name,
1735 created from the remainder of the GNS name and the
1736 name in the NS record */
1737 GNUNET_asprintf (&ac->label,
1738 "%.*s%s%s",
1739 (int) rh->name_resolution_pos,
1740 rh->name,
1741 (0 != rh->name_resolution_pos) ? "." : "",
1742 ns);
1743 GNUNET_free (ns);
1744 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1745 rh->ac_tail,
1746 ac);
1747 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1748 {
1749 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1750 _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1751 ac->label);
1752 return GNUNET_SYSERR;
1753 }
1754 continue_with_gns2dns (ac);
1755 return GNUNET_OK;
1498} 1756}
1499 1757
1500 1758
1501
1502/** 1759/**
1503 * Process a records that were decrypted from a block. 1760 * Process a records that were decrypted from a block.
1504 * 1761 *
@@ -1512,7 +1769,6 @@ handle_gns_resolution_result (void *cls,
1512 const struct GNUNET_GNSRECORD_Data *rd) 1769 const struct GNUNET_GNSRECORD_Data *rd)
1513{ 1770{
1514 struct GNS_ResolverHandle *rh = cls; 1771 struct GNS_ResolverHandle *rh = cls;
1515 struct AuthorityChain *ac;
1516 struct AuthorityChain *shorten_ac; 1772 struct AuthorityChain *shorten_ac;
1517 char *cname; 1773 char *cname;
1518 struct VpnContext *vpn_ctx; 1774 struct VpnContext *vpn_ctx;
@@ -1532,6 +1788,14 @@ handle_gns_resolution_result (void *cls,
1532 rh->ac_tail->label, 1788 rh->ac_tail->label,
1533 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority), 1789 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1534 rd_count); 1790 rd_count);
1791 if (0 == rd_count)
1792 {
1793 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1794 _("GNS lookup failed (zero records found)\n"));
1795 fail_resolution (rh);
1796 return;
1797 }
1798
1535 if (0 == rh->name_resolution_pos) 1799 if (0 == rh->name_resolution_pos)
1536 { 1800 {
1537 /* top-level match, are we done yet? */ 1801 /* top-level match, are we done yet? */
@@ -1547,9 +1811,8 @@ handle_gns_resolution_result (void *cls,
1547 (off != rd[0].data_size) ) 1811 (off != rd[0].data_size) )
1548 { 1812 {
1549 GNUNET_break_op (0); 1813 GNUNET_break_op (0);
1550 rh->proc (rh->proc_cls, 0, NULL);
1551 GNS_resolver_lookup_cancel (rh);
1552 GNUNET_free_non_null (cname); 1814 GNUNET_free_non_null (cname);
1815 fail_resolution (rh);
1553 return; 1816 return;
1554 } 1817 }
1555 handle_gns_cname_result (rh, 1818 handle_gns_cname_result (rh,
@@ -1573,8 +1836,7 @@ handle_gns_resolution_result (void *cls,
1573 rd[i].data_size) 1836 rd[i].data_size)
1574 { 1837 {
1575 GNUNET_break_op (0); 1838 GNUNET_break_op (0);
1576 rh->proc (rh->proc_cls, 0, NULL); 1839 fail_resolution (rh);
1577 GNS_resolver_lookup_cancel (rh);
1578 return; 1840 return;
1579 } 1841 }
1580 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data; 1842 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
@@ -1582,8 +1844,7 @@ handle_gns_resolution_result (void *cls,
1582 if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)]) 1844 if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
1583 { 1845 {
1584 GNUNET_break_op (0); 1846 GNUNET_break_op (0);
1585 rh->proc (rh->proc_cls, 0, NULL); 1847 fail_resolution (rh);
1586 GNS_resolver_lookup_cancel (rh);
1587 return; 1848 return;
1588 } 1849 }
1589 GNUNET_TUN_service_name_to_hash (vname, 1850 GNUNET_TUN_service_name_to_hash (vname,
@@ -1621,7 +1882,13 @@ handle_gns_resolution_result (void *cls,
1621 /* delegation to DNS */ 1882 /* delegation to DNS */
1622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1623 "Found GNS2DNS record, delegating to DNS!\n"); 1884 "Found GNS2DNS record, delegating to DNS!\n");
1624 goto do_recurse; 1885 if (GNUNET_OK ==
1886 recursive_gns2dns_resolution (rh,
1887 rd_count,
1888 rd))
1889 return;
1890 else
1891 goto fail;
1625 } 1892 }
1626 default: 1893 default:
1627 break; 1894 break;
@@ -1823,7 +2090,9 @@ handle_gns_resolution_result (void *cls,
1823 GNUNET_break_op (0); 2090 GNUNET_break_op (0);
1824 break; 2091 break;
1825 } 2092 }
1826 GNUNET_memcpy (&pub, rd[i].data, rd[i].data_size); 2093 GNUNET_memcpy (&pub,
2094 rd[i].data,
2095 rd[i].data_size);
1827 rd_off++; 2096 rd_off++;
1828 if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type) 2097 if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
1829 { 2098 {
@@ -1856,7 +2125,13 @@ handle_gns_resolution_result (void *cls,
1856 } 2125 }
1857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1858 "Found GNS2DNS record, delegating to DNS!\n"); 2127 "Found GNS2DNS record, delegating to DNS!\n");
1859 goto do_recurse; 2128 if (GNUNET_OK ==
2129 recursive_gns2dns_resolution (rh,
2130 rd_count,
2131 rd))
2132 return;
2133 else
2134 goto fail;
1860 } 2135 }
1861 case GNUNET_GNSRECORD_TYPE_BOX: 2136 case GNUNET_GNSRECORD_TYPE_BOX:
1862 { 2137 {
@@ -1901,200 +2176,35 @@ handle_gns_resolution_result (void *cls,
1901 rh->proc (rh->proc_cls, 2176 rh->proc (rh->proc_cls,
1902 rd_off, 2177 rd_off,
1903 rd_new); 2178 rd_new);
1904 GNS_resolver_lookup_cancel (rh); 2179 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2180 rh);
1905 return; 2181 return;
1906 } 2182 }
1907 do_recurse: 2183
1908 /* need to recurse, check if we can */ 2184 switch (rd[0].record_type)
1909 for (unsigned int i=0;i<rd_count;i++)
1910 { 2185 {
1911 switch (rd[i].record_type) 2186 case GNUNET_DNSPARSER_TYPE_CNAME:
1912 { 2187 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
1913 case GNUNET_GNSRECORD_TYPE_PKEY: 2188 recursive_cname_resolution (rh,
1914 /* delegation to another zone */ 2189 &rd[0]);
1915 if (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) != 2190 return;
1916 rd[i].data_size) 2191 case GNUNET_GNSRECORD_TYPE_PKEY:
1917 { 2192 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
1918 GNUNET_break_op (0); 2193 recursive_pkey_resolution (rh,
1919 rh->proc (rh->proc_cls, 0, NULL); 2194 &rd[0]);
1920 GNS_resolver_lookup_cancel (rh); 2195 return;
1921 return; 2196 default:
1922 } 2197 if (GNUNET_OK ==
1923 /* expand authority chain */ 2198 recursive_gns2dns_resolution (rh,
1924 ac = GNUNET_new (struct AuthorityChain); 2199 rd_count,
1925 ac->rh = rh; 2200 rd))
1926 ac->gns_authority = GNUNET_YES;
1927 ac->suggested_shortening_label = NULL;
1928 ac->shortening_started = GNUNET_NO;
1929 GNUNET_memcpy (&ac->authority_info.gns_authority,
1930 rd[i].data,
1931 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1932 ac->label = resolver_lookup_get_next_label (rh);
1933 /* add AC to tail */
1934 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1935 rh->ac_tail,
1936 ac);
1937 /* recurse */
1938 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1939 rh);
1940 return; 2201 return;
1941 case GNUNET_GNSRECORD_TYPE_GNS2DNS: 2202 break;
1942 {
1943 /* TODO: Right now we only foward the request to ONE DNS resolver,
1944 even if we get multiple IP addresses back; a correct implementation
1945 should try all DNS resolvers. */
1946 /* resolution continues within DNS */
1947 struct Gns2DnsContext *g2dc;
1948 char *ip;
1949 char *ns;
1950 const char *tld;
1951 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
1952 struct in_addr v4;
1953 struct in6_addr v6;
1954
1955 off = 0;
1956 ns = GNUNET_DNSPARSER_parse_name (rd[i].data,
1957 rd[i].data_size,
1958 &off);
1959 ip = GNUNET_DNSPARSER_parse_name (rd[i].data,
1960 rd[i].data_size,
1961 &off);
1962 if ( (NULL == ns) ||
1963 (NULL == ip) ||
1964 (off != rd[i].data_size) )
1965 {
1966 GNUNET_break_op (0);
1967 GNUNET_free_non_null (ns);
1968 GNUNET_free_non_null (ip);
1969 fail_resolution (rh);
1970 return;
1971 }
1972 /* resolve 'ip' to determine the IP(s) of the DNS
1973 resolver to use for lookup of 'ns' */
1974 g2dc = GNUNET_new (struct Gns2DnsContext);
1975 g2dc->ns = ns;
1976 rh->g2dc = g2dc;
1977
1978 /* check if 'ip' is already an IPv4/IPv6 address */
1979 if (1 == inet_pton (AF_INET,
1980 ip,
1981 &v4))
1982 {
1983 /* name is IPv4 address, pretend it's an A record */
1984 struct GNUNET_GNSRECORD_Data rd;
1985
1986 GNUNET_free (ip);
1987 rd.data = &v4;
1988 rd.data_size = sizeof (v4);
1989 rd.expiration_time = UINT64_MAX;
1990 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
1991 rd.flags = 0;
1992 handle_gns2dns_result (rh,
1993 1,
1994 &rd);
1995 return;
1996 }
1997 if (1 == inet_pton (AF_INET6,
1998 ip,
1999 &v6))
2000 {
2001 /* name is IPv6 address, pretend it's an AAAA record */
2002 struct GNUNET_GNSRECORD_Data rd;
2003
2004 GNUNET_free (ip);
2005 rd.data = &v6;
2006 rd.data_size = sizeof (v6);
2007 rd.expiration_time = UINT64_MAX;
2008 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2009 rd.flags = 0;
2010 handle_gns2dns_result (rh,
2011 1,
2012 &rd);
2013 return;
2014 }
2015
2016 tld = GNS_get_tld (ip);
2017 if (0 != strcmp (tld,
2018 "+"))
2019 {
2020 /* 'ip' is a DNS name */
2021 g2dc->dns_rh = GNUNET_RESOLVER_ip_get (ip,
2022 AF_UNSPEC,
2023 GNUNET_TIME_UNIT_FOREVER_REL,
2024 &handle_gns2dns_ip,
2025 g2dc);
2026 GNUNET_free (ip);
2027 return;
2028 }
2029
2030 /* 'ip' should be a GNS name */
2031 g2dc->rh = GNUNET_new (struct GNS_ResolverHandle);
2032
2033 ip = translate_dot_plus (rh,
2034 ip);
2035 tld = GNS_get_tld (ip);
2036 if (GNUNET_OK !=
2037 GNUNET_GNSRECORD_zkey_to_pkey (tld,
2038 &zone))
2039 {
2040 GNUNET_break_op (0);
2041 GNUNET_free_non_null (ns);
2042 GNUNET_free_non_null (ip);
2043 GNUNET_free (g2dc);
2044 fail_resolution (rh);
2045 return;
2046 }
2047 g2dc->rh->authority_zone = zone;
2048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2049 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
2050 ip,
2051 ns);
2052 g2dc->rh->name = ip;
2053 g2dc->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
2054 g2dc->rh->proc = &handle_gns2dns_result;
2055 g2dc->rh->proc_cls = rh;
2056 g2dc->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
2057 g2dc->rh->options = GNUNET_GNS_LO_DEFAULT;
2058 g2dc->rh->loop_limiter = rh->loop_limiter + 1;
2059 g2dc->rh->task_id
2060 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2061 g2dc->rh);
2062 return;
2063 }
2064 case GNUNET_DNSPARSER_TYPE_CNAME:
2065 {
2066 char *cname;
2067
2068 off = 0;
2069 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2070 rd[i].data_size,
2071 &off);
2072 if ( (NULL == cname) ||
2073 (off != rd[i].data_size) )
2074 {
2075 GNUNET_break_op (0); /* record not well-formed */
2076 rh->proc (rh->proc_cls, 0, NULL);
2077 GNS_resolver_lookup_cancel (rh);
2078 GNUNET_free_non_null (cname);
2079 return;
2080 }
2081 handle_gns_cname_result (rh,
2082 cname);
2083 GNUNET_free (cname);
2084 return;
2085 }
2086 /* FIXME: handle DNAME */
2087 default:
2088 /* skip */
2089 break;
2090 }
2091 } 2203 }
2204 fail:
2092 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2205 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2093 _("GNS lookup recursion failed (no delegation record found)\n")); 2206 _("GNS lookup recursion failed (no delegation record found)\n"));
2094 rh->proc (rh->proc_cls, 2207 fail_resolution (rh);
2095 0,
2096 NULL);
2097 GNS_resolver_lookup_cancel (rh);
2098} 2208}
2099 2209
2100 2210
@@ -2176,8 +2286,7 @@ handle_dht_response (void *cls,
2176 { 2286 {
2177 /* how did this pass DHT block validation!? */ 2287 /* how did this pass DHT block validation!? */
2178 GNUNET_break (0); 2288 GNUNET_break (0);
2179 rh->proc (rh->proc_cls, 0, NULL); 2289 fail_resolution (rh);
2180 GNS_resolver_lookup_cancel (rh);
2181 return; 2290 return;
2182 } 2291 }
2183 block = data; 2292 block = data;
@@ -2188,8 +2297,7 @@ handle_dht_response (void *cls,
2188 { 2297 {
2189 /* how did this pass DHT block validation!? */ 2298 /* how did this pass DHT block validation!? */
2190 GNUNET_break (0); 2299 GNUNET_break (0);
2191 rh->proc (rh->proc_cls, 0, NULL); 2300 fail_resolution (rh);
2192 GNS_resolver_lookup_cancel (rh);
2193 return; 2301 return;
2194 } 2302 }
2195 if (GNUNET_OK != 2303 if (GNUNET_OK !=
@@ -2200,8 +2308,7 @@ handle_dht_response (void *cls,
2200 rh)) 2308 rh))
2201 { 2309 {
2202 GNUNET_break_op (0); /* block was ill-formed */ 2310 GNUNET_break_op (0); /* block was ill-formed */
2203 rh->proc (rh->proc_cls, 0, NULL); 2311 fail_resolution (rh);
2204 GNS_resolver_lookup_cancel (rh);
2205 return; 2312 return;
2206 } 2313 }
2207 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) 2314 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us)
@@ -2252,8 +2359,7 @@ start_dht_request (struct GNS_ResolverHandle *rh,
2252 /* fail longest-standing DHT request */ 2359 /* fail longest-standing DHT request */
2253 rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap); 2360 rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
2254 GNUNET_assert (NULL != rx); 2361 GNUNET_assert (NULL != rx);
2255 rx->proc (rx->proc_cls, 0, NULL); 2362 fail_resolution (rx);
2256 GNS_resolver_lookup_cancel (rx);
2257 } 2363 }
2258} 2364}
2259 2365
@@ -2324,8 +2430,7 @@ handle_namecache_block_response (void *cls,
2324 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n", 2430 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2325 ac->label, 2431 ac->label,
2326 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority)); 2432 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2327 rh->proc (rh->proc_cls, 0, NULL); 2433 fail_resolution (rh);
2328 GNS_resolver_lookup_cancel (rh);
2329 return; 2434 return;
2330 } 2435 }
2331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2408,8 +2513,7 @@ handle_revocation_result (void *cls,
2408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2513 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2409 _("Zone %s was revoked, resolution fails\n"), 2514 _("Zone %s was revoked, resolution fails\n"),
2410 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority)); 2515 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2411 rh->proc (rh->proc_cls, 0, NULL); 2516 fail_resolution (rh);
2412 GNS_resolver_lookup_cancel (rh);
2413 return; 2517 return;
2414 } 2518 }
2415 recursive_gns_resolution_namecache (rh); 2519 recursive_gns_resolution_namecache (rh);
@@ -2453,8 +2557,7 @@ recursive_resolution (void *cls)
2453 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2557 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2454 "Encountered unbounded recursion resolving `%s'\n", 2558 "Encountered unbounded recursion resolving `%s'\n",
2455 rh->name); 2559 rh->name);
2456 rh->proc (rh->proc_cls, 0, NULL); 2560 fail_resolution (rh);
2457 GNS_resolver_lookup_cancel (rh);
2458 return; 2561 return;
2459 } 2562 }
2460 if (GNUNET_YES == rh->ac_tail->gns_authority) 2563 if (GNUNET_YES == rh->ac_tail->gns_authority)
@@ -2491,8 +2594,12 @@ start_resolver_lookup (void *cls)
2491 rd.expiration_time = UINT64_MAX; 2594 rd.expiration_time = UINT64_MAX;
2492 rd.record_type = GNUNET_DNSPARSER_TYPE_A; 2595 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2493 rd.flags = 0; 2596 rd.flags = 0;
2494 rh->proc (rh->proc_cls, 1, &rd); 2597 rh->proc (rh->proc_cls,
2495 GNS_resolver_lookup_cancel (rh); 2598 1,
2599 &rd);
2600 GNUNET_assert (NULL == rh->task_id);
2601 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2602 rh);
2496 return; 2603 return;
2497 } 2604 }
2498 if (1 == inet_pton (AF_INET6, 2605 if (1 == inet_pton (AF_INET6,
@@ -2507,8 +2614,12 @@ start_resolver_lookup (void *cls)
2507 rd.expiration_time = UINT64_MAX; 2614 rd.expiration_time = UINT64_MAX;
2508 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA; 2615 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2509 rd.flags = 0; 2616 rd.flags = 0;
2510 rh->proc (rh->proc_cls, 1, &rd); 2617 rh->proc (rh->proc_cls,
2511 GNS_resolver_lookup_cancel (rh); 2618 1,
2619 &rd);
2620 GNUNET_assert (NULL == rh->task_id);
2621 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2622 rh);
2512 return; 2623 return;
2513 } 2624 }
2514 2625
@@ -2587,37 +2698,51 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2587 GNUNET_CONTAINER_DLL_remove (rlh_head, 2698 GNUNET_CONTAINER_DLL_remove (rlh_head,
2588 rlh_tail, 2699 rlh_tail,
2589 rh); 2700 rh);
2701 if (NULL != rh->dns_request)
2702 {
2703 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2704 rh->dns_request = NULL;
2705 }
2590 while (NULL != (ac = rh->ac_head)) 2706 while (NULL != (ac = rh->ac_head))
2591 { 2707 {
2592 GNUNET_CONTAINER_DLL_remove (rh->ac_head, 2708 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2593 rh->ac_tail, 2709 rh->ac_tail,
2594 ac); 2710 ac);
2711 if (GNUNET_NO == ac->gns_authority)
2712 {
2713 struct Gns2DnsPending *gp;
2714
2715 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2716 {
2717 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2718 ac->authority_info.dns_authority.gp_tail,
2719 gp);
2720 if (NULL != gp->rh)
2721 {
2722 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2723 using GNS_resolver_lookup_cancel here, we need to
2724 add it first... */
2725 GNUNET_CONTAINER_DLL_insert (rlh_head,
2726 rlh_tail,
2727 gp->rh);
2728 GNUNET_assert (NULL == gp->rh->task_id);
2729 gp->rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2730 gp->rh);
2731 gp->rh = NULL;
2732 }
2733 if (NULL != gp->dns_rh)
2734 {
2735 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2736 gp->dns_rh = NULL;
2737 }
2738 GNUNET_free (gp);
2739 }
2740 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2741 }
2595 GNUNET_free (ac->label); 2742 GNUNET_free (ac->label);
2596 GNUNET_free_non_null (ac->suggested_shortening_label); 2743 GNUNET_free_non_null (ac->suggested_shortening_label);
2597 GNUNET_free (ac); 2744 GNUNET_free (ac);
2598 } 2745 }
2599 if (NULL != rh->g2dc)
2600 {
2601 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2602 using GNS_resolver_lookup_cancel here, we need to
2603 add it first... */
2604 if (NULL != rh->g2dc->rh)
2605 {
2606 GNUNET_CONTAINER_DLL_insert (rlh_head,
2607 rlh_tail,
2608 rh->g2dc->rh);
2609 GNS_resolver_lookup_cancel (rh->g2dc->rh);
2610 rh->g2dc->rh = NULL;
2611 }
2612 if (NULL != rh->g2dc->dns_rh)
2613 {
2614 GNUNET_RESOLVER_request_cancel (rh->g2dc->dns_rh);
2615 rh->g2dc->rh = NULL;
2616 }
2617 GNUNET_free (rh->g2dc->ns);
2618 GNUNET_free (rh->g2dc);
2619 rh->g2dc = NULL;
2620 }
2621 if (NULL != rh->task_id) 2746 if (NULL != rh->task_id)
2622 { 2747 {
2623 GNUNET_SCHEDULER_cancel (rh->task_id); 2748 GNUNET_SCHEDULER_cancel (rh->task_id);
@@ -2639,11 +2764,6 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2639 GNUNET_free (vpn_ctx->rd_data); 2764 GNUNET_free (vpn_ctx->rd_data);
2640 GNUNET_free (vpn_ctx); 2765 GNUNET_free (vpn_ctx);
2641 } 2766 }
2642 if (NULL != rh->dns_request)
2643 {
2644 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2645 rh->dns_request = NULL;
2646 }
2647 if (NULL != rh->namecache_qe) 2767 if (NULL != rh->namecache_qe)
2648 { 2768 {
2649 GNUNET_NAMECACHE_cancel (rh->namecache_qe); 2769 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
@@ -2690,8 +2810,6 @@ GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2690 const struct GNUNET_CONFIGURATION_Handle *c, 2810 const struct GNUNET_CONFIGURATION_Handle *c,
2691 unsigned long long max_bg_queries) 2811 unsigned long long max_bg_queries)
2692{ 2812{
2693 char *dns_ip;
2694
2695 cfg = c; 2813 cfg = c;
2696 namecache_handle = nc; 2814 namecache_handle = nc;
2697 dht_handle = dht; 2815 dht_handle = dht;
@@ -2706,18 +2824,6 @@ GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2706 if (GNUNET_NO == use_cache) 2824 if (GNUNET_NO == use_cache)
2707 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2708 "Namecache disabled\n"); 2826 "Namecache disabled\n");
2709
2710 if (GNUNET_OK !=
2711 GNUNET_CONFIGURATION_get_value_string (c,
2712 "gns",
2713 "DNS_RESOLVER",
2714 &dns_ip))
2715 {
2716 /* user did not specify DNS resolver, use 8.8.8.8 */
2717 dns_ip = GNUNET_strdup ("8.8.8.8");
2718 }
2719 dns_handle = GNUNET_DNSSTUB_start (dns_ip);
2720 GNUNET_free (dns_ip);
2721 vpn_handle = GNUNET_VPN_connect (cfg); 2827 vpn_handle = GNUNET_VPN_connect (cfg);
2722} 2828}
2723 2829
@@ -2734,7 +2840,9 @@ GNS_resolver_done ()
2734 /* abort active resolutions */ 2840 /* abort active resolutions */
2735 while (NULL != (rh = rlh_head)) 2841 while (NULL != (rh = rlh_head))
2736 { 2842 {
2737 rh->proc (rh->proc_cls, 0, NULL); 2843 rh->proc (rh->proc_cls,
2844 0,
2845 NULL);
2738 GNS_resolver_lookup_cancel (rh); 2846 GNS_resolver_lookup_cancel (rh);
2739 } 2847 }
2740 while (NULL != (co = co_head)) 2848 while (NULL != (co = co_head))
@@ -2747,8 +2855,6 @@ GNS_resolver_done ()
2747 } 2855 }
2748 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap); 2856 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2749 dht_lookup_heap = NULL; 2857 dht_lookup_heap = NULL;
2750 GNUNET_DNSSTUB_stop (dns_handle);
2751 dns_handle = NULL;
2752 GNUNET_VPN_disconnect (vpn_handle); 2858 GNUNET_VPN_disconnect (vpn_handle);
2753 vpn_handle = NULL; 2859 vpn_handle = NULL;
2754 dht_handle = NULL; 2860 dht_handle = NULL;
diff --git a/src/gns/test_gns_lookup.conf b/src/gns/test_gns_lookup.conf
index ea8c7c3fc..a9a2345c7 100644
--- a/src/gns/test_gns_lookup.conf
+++ b/src/gns/test_gns_lookup.conf
@@ -10,7 +10,7 @@ AUTOSTART = YES
10PLUGINS = 10PLUGINS =
11 11
12[gns] 12[gns]
13#PREFIX = valgrind --leak-check=full --track-origins=yes 13# PREFIX = valgrind --leak-check=full --track-origins=yes
14AUTOSTART = YES 14AUTOSTART = YES
15AUTO_IMPORT_PKEY = YES 15AUTO_IMPORT_PKEY = YES
16MAX_PARALLEL_BACKGROUND_QUERIES = 10 16MAX_PARALLEL_BACKGROUND_QUERIES = 10
diff --git a/src/include/gnunet_dnsstub_lib.h b/src/include/gnunet_dnsstub_lib.h
index 1c3305f7b..41e30d044 100644
--- a/src/include/gnunet_dnsstub_lib.h
+++ b/src/include/gnunet_dnsstub_lib.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2012 GNUnet e.V. 3 Copyright (C) 2012, 2018 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -48,14 +48,52 @@ struct GNUNET_DNSSTUB_RequestSocket;
48/** 48/**
49 * Start a DNS stub resolver. 49 * Start a DNS stub resolver.
50 * 50 *
51 * @param dns_ip target IP address to use 51 * @param num_sockets how many sockets should we open
52 * in parallel for DNS queries for this stub?
52 * @return NULL on error 53 * @return NULL on error
53 */ 54 */
54struct GNUNET_DNSSTUB_Context * 55struct GNUNET_DNSSTUB_Context *
55GNUNET_DNSSTUB_start (const char *dns_ip); 56GNUNET_DNSSTUB_start (unsigned int num_sockets);
56 57
57 58
58/** 59/**
60 * Add nameserver for use by the DNSSTUB. We will use
61 * all provided nameservers for resolution (round-robin).
62 *
63 * @param ctx resolver context to modify
64 * @param dns_ip target IP address to use (as string)
65 * @return #GNUNET_OK on success
66 */
67int
68GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx,
69 const char *dns_ip);
70
71
72/**
73 * Add nameserver for use by the DNSSTUB. We will use
74 * all provided nameservers for resolution (round-robin).
75 *
76 * @param ctx resolver context to modify
77 * @param sa socket address of DNS resolver to use
78 * @return #GNUNET_OK on success
79 */
80int
81GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx,
82 const struct sockaddr *sa);
83
84
85/**
86 * How long should we try requests before timing out?
87 * Only effective for requests issued after this call.
88 *
89 * @param ctx resolver context to modify
90 * @param retry_frequ how long to wait between retries
91 */
92void
93GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx,
94 struct GNUNET_TIME_Relative retry_freq);
95
96/**
59 * Cleanup DNSSTUB resolver. 97 * Cleanup DNSSTUB resolver.
60 * 98 *
61 * @param ctx stub resolver to clean up 99 * @param ctx stub resolver to clean up
@@ -66,57 +104,36 @@ GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx);
66 104
67/** 105/**
68 * Function called with the result of a DNS resolution. 106 * Function called with the result of a DNS resolution.
107 * Once this function is called, the resolution request
108 * is automatically cancelled / cleaned up. In particular,
109 * the function will only be called once.
69 * 110 *
70 * @param cls closure 111 * @param cls closure
71 * @param rs socket that received the response 112 * @param dns dns response, NULL on hard error (i.e. timeout)
72 * @param dns dns response, never NULL
73 * @param dns_len number of bytes in @a dns 113 * @param dns_len number of bytes in @a dns
74 */ 114 */
75typedef void 115typedef void
76(*GNUNET_DNSSTUB_ResultCallback)(void *cls, 116(*GNUNET_DNSSTUB_ResultCallback)(void *cls,
77 struct GNUNET_DNSSTUB_RequestSocket *rs,
78 const struct GNUNET_TUN_DnsHeader *dns, 117 const struct GNUNET_TUN_DnsHeader *dns,
79 size_t dns_len); 118 size_t dns_len);
80 119
81 120
82/** 121/**
83 * Perform DNS resolution using given address.
84 *
85 * @param ctx stub resolver to use
86 * @param sa the socket address
87 * @param sa_len the socket length
88 * @param request DNS request to transmit
89 * @param request_len number of bytes in msg
90 * @param rc function to call with result
91 * @param rc_cls closure for @a rc
92 * @return socket used for the request, NULL on error
93 */
94struct GNUNET_DNSSTUB_RequestSocket *
95GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
96 const struct sockaddr *sa,
97 socklen_t sa_len,
98 const void *request,
99 size_t request_len,
100 GNUNET_DNSSTUB_ResultCallback rc,
101 void *rc_cls);
102
103
104/**
105 * Perform DNS resolution using our default IP from init. 122 * Perform DNS resolution using our default IP from init.
106 * 123 *
107 * @param ctx stub resolver to use 124 * @param ctx stub resolver to use
108 * @param request DNS request to transmit 125 * @param request DNS request to transmit
109 * @param request_len number of bytes in msg 126 * @param request_len number of bytes in msg
110 * @param rc function to call with result 127 * @param rc function to call with result (once)
111 * @param rc_cls closure for @a rc 128 * @param rc_cls closure for @a rc
112 * @return socket used for the request, NULL on error 129 * @return socket used for the request, NULL on error
113 */ 130 */
114struct GNUNET_DNSSTUB_RequestSocket * 131struct GNUNET_DNSSTUB_RequestSocket *
115GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx, 132GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
116 const void *request, 133 const void *request,
117 size_t request_len, 134 size_t request_len,
118 GNUNET_DNSSTUB_ResultCallback rc, 135 GNUNET_DNSSTUB_ResultCallback rc,
119 void *rc_cls); 136 void *rc_cls);
120 137
121 138
122/** 139/**
diff --git a/src/namestore/gnunet-zoneimport.c b/src/namestore/gnunet-zoneimport.c
index 4f4151c94..279bfddea 100644
--- a/src/namestore/gnunet-zoneimport.c
+++ b/src/namestore/gnunet-zoneimport.c
@@ -818,13 +818,11 @@ store_completed_cb (void *cls,
818 * Function called with the result of a DNS resolution. 818 * Function called with the result of a DNS resolution.
819 * 819 *
820 * @param cls closure with the `struct Request` 820 * @param cls closure with the `struct Request`
821 * @param rs socket that received the response
822 * @param dns dns response, never NULL 821 * @param dns dns response, never NULL
823 * @param dns_len number of bytes in @a dns 822 * @param dns_len number of bytes in @a dns
824 */ 823 */
825static void 824static void
826process_result (void *cls, 825process_result (void *cls,
827 struct GNUNET_DNSSTUB_RequestSocket *rs,
828 const struct GNUNET_TUN_DnsHeader *dns, 826 const struct GNUNET_TUN_DnsHeader *dns,
829 size_t dns_len) 827 size_t dns_len)
830{ 828{
@@ -833,7 +831,6 @@ process_result (void *cls,
833 struct GNUNET_DNSPARSER_Packet *p; 831 struct GNUNET_DNSPARSER_Packet *p;
834 unsigned int rd_count; 832 unsigned int rd_count;
835 833
836 (void) rs;
837 GNUNET_assert (NULL == req->hn); 834 GNUNET_assert (NULL == req->hn);
838 if (NULL == dns) 835 if (NULL == dns)
839 { 836 {
@@ -970,11 +967,11 @@ submit_req (struct Request *req)
970 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 967 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
971 "Requesting resolution for `%s'\n", 968 "Requesting resolution for `%s'\n",
972 req->hostname); 969 req->hostname);
973 req->rs = GNUNET_DNSSTUB_resolve2 (ctx, 970 req->rs = GNUNET_DNSSTUB_resolve (ctx,
974 req->raw, 971 req->raw,
975 req->raw_len, 972 req->raw_len,
976 &process_result, 973 &process_result,
977 req); 974 req);
978 GNUNET_assert (NULL != req->rs); 975 GNUNET_assert (NULL != req->rs);
979 req->issue_num++; 976 req->issue_num++;
980 last_request = now; 977 last_request = now;
@@ -1396,13 +1393,33 @@ run (void *cls,
1396 (void) args; 1393 (void) args;
1397 (void) cfgfile; 1394 (void) cfgfile;
1398 req_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); 1395 req_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1399 ctx = GNUNET_DNSSTUB_start (dns_server); 1396 ctx = GNUNET_DNSSTUB_start (256);
1400 if (NULL == ctx) 1397 if (NULL == ctx)
1401 { 1398 {
1402 fprintf (stderr, 1399 fprintf (stderr,
1403 "Failed to initialize GNUnet DNS STUB\n"); 1400 "Failed to initialize GNUnet DNS STUB\n");
1404 return; 1401 return;
1405 } 1402 }
1403 if (NULL == args[1])
1404 {
1405 fprintf (stderr,
1406 "You must provide a list of DNS resolvers on the command line\n");
1407 return;
1408 }
1409 for (unsigned int i=1;NULL != args[i];i++)
1410 {
1411 if (GNUNET_OK !=
1412 GNUNET_DNSSTUB_add_dns_ip (ctx,
1413 args[1]))
1414 {
1415 fprintf (stderr,
1416 "Failed to use `%s' for DNS resolver\n",
1417 args[i]);
1418 return;
1419 }
1420 }
1421
1422
1406 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 1423 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1407 NULL); 1424 NULL);
1408 ns = GNUNET_NAMESTORE_connect (cfg); 1425 ns = GNUNET_NAMESTORE_connect (cfg);