aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-04-19 18:38:41 +0200
committerChristian Grothoff <christian@grothoff.org>2018-04-19 18:38:41 +0200
commitff4d7b51f37f61633766664647e9b148af1e4f0a (patch)
tree500aa14d9452ce90c19dbbb18cfaec0dd51e6ec2 /src/dns
parent9c699755967529e59815561d03b85e9a90d789f8 (diff)
downloadgnunet-ff4d7b51f37f61633766664647e9b148af1e4f0a.tar.gz
gnunet-ff4d7b51f37f61633766664647e9b148af1e4f0a.zip
support multiple DNS resolvers for queries (in DNSSTUB and GNS2DNS resolution for now)
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/dnsstub.c683
-rw-r--r--src/dns/gnunet-service-dns.c43
-rw-r--r--src/dns/gnunet-zoneimport.c24
3 files changed, 418 insertions, 332 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),