aboutsummaryrefslogtreecommitdiff
path: root/src/dns/dnsstub.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/dnsstub.c')
-rw-r--r--src/dns/dnsstub.c683
1 files changed, 381 insertions, 302 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