aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-02-09 10:12:22 +0000
committerChristian Grothoff <christian@grothoff.org>2012-02-09 10:12:22 +0000
commitacddb731e03012c7479dec7257b44dc6ed450b3c (patch)
tree91c25e11254c027b4f1bf7a5b7409fcebcd5e3f5 /src/dns
parenta371ea89023739ba6d2a889ddf1a2f4242ff8605 (diff)
downloadgnunet-acddb731e03012c7479dec7257b44dc6ed450b3c.tar.gz
gnunet-acddb731e03012c7479dec7257b44dc6ed450b3c.zip
-fixing source port randomization for DNS service
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/Makefile.am2
-rw-r--r--src/dns/gnunet-service-dns.c552
2 files changed, 306 insertions, 248 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index a9b1d652e..6e25d81bf 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -22,7 +22,7 @@ install-exec-hook:
22 $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true 22 $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true
23 $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true 23 $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true
24 $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true 24 $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true
25 $(SUDO_BINARY) chmod 2755 $(bindir)/gnunet-service-dns || true 25 $(SUDO_BINARY) chmod 2750 $(bindir)/gnunet-service-dns || true
26else 26else
27install-exec-hook: 27install-exec-hook:
28endif 28endif
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c
index 1c772d712..46cc1a30c 100644
--- a/src/dns/gnunet-service-dns.c
+++ b/src/dns/gnunet-service-dns.c
@@ -22,6 +22,19 @@
22 * @file dns/gnunet-service-dns.c 22 * @file dns/gnunet-service-dns.c
23 * @brief service to intercept and modify DNS queries (and replies) of this system 23 * @brief service to intercept and modify DNS queries (and replies) of this system
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * For "secure" interaction with the legacy DNS system, we permit
27 * replies only to arrive within a 5s window (and they must match
28 * ports, IPs and request IDs). Furthermore, we let the OS pick a
29 * source port, opening up to 128 sockets per address family (IPv4 or
30 * IPv6). Those sockets are closed if they are not in use for 5s
31 * (which means they will be freshly randomized afterwards). For new
32 * requests, we pick a random slot in the array with 128 socket slots
33 * (and re-use an existing socket if the slot is still in use). Thus
34 * each request will be given one of 128 random source ports, and the
35 * 128 random source ports will also change "often" (less often if the
36 * system is very busy, each time if we are mostly idle). At the same
37 * time, the system will never use more than 256 UDP sockets.
25 */ 38 */
26#include "platform.h" 39#include "platform.h"
27#include "gnunet_util_lib.h" 40#include "gnunet_util_lib.h"
@@ -37,6 +50,17 @@
37 50
38 51
39/** 52/**
53 * Timeout for an external (Internet-DNS) DNS resolution
54 */
55#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
56
57/**
58 * How many DNS sockets do we open at most at the same time?
59 * (technical socket maximum is this number x2 for IPv4+IPv6)
60 */
61#define DNS_SOCKET_MAX 128
62
63/**
40 * Phases each request goes through. 64 * Phases each request goes through.
41 */ 65 */
42enum RequestPhase 66enum RequestPhase
@@ -112,6 +136,34 @@ struct ClientRecord
112 136
113 137
114/** 138/**
139 * UDP socket we are using for sending DNS requests to the Internet.
140 */
141struct RequestSocket
142{
143
144 /**
145 * UDP socket we use for this request for IPv4
146 */
147 struct GNUNET_NETWORK_Handle *dnsout4;
148
149 /**
150 * UDP socket we use for this request for IPv6
151 */
152 struct GNUNET_NETWORK_Handle *dnsout6;
153
154 /**
155 * Task for reading from dnsout4 and dnsout6.
156 */
157 GNUNET_SCHEDULER_TaskIdentifier read_task;
158
159 /**
160 * When should this socket be closed?
161 */
162 struct GNUNET_TIME_Absolute timeout;
163};
164
165
166/**
115 * Entry we keep for each active request. 167 * Entry we keep for each active request.
116 */ 168 */
117struct RequestRecord 169struct RequestRecord
@@ -130,6 +182,13 @@ struct RequestRecord
130 char *payload; 182 char *payload;
131 183
132 /** 184 /**
185 * Socket we are using to transmit this request (must match if we receive
186 * a response). Must NOT be freed as part of this request record (as it
187 * might be shared with other requests).
188 */
189 struct GNUNET_NETWORK_Handle *dnsout;
190
191 /**
133 * Source address of the original request (for sending response). 192 * Source address of the original request (for sending response).
134 */ 193 */
135 struct sockaddr_storage src_addr; 194 struct sockaddr_storage src_addr;
@@ -140,6 +199,11 @@ struct RequestRecord
140 struct sockaddr_storage dst_addr; 199 struct sockaddr_storage dst_addr;
141 200
142 /** 201 /**
202 * When should this request time out?
203 */
204 struct GNUNET_TIME_Absolute timeout;
205
206 /**
143 * ID of this request, also basis for hashing. Lowest 16 bit will 207 * ID of this request, also basis for hashing. Lowest 16 bit will
144 * be our message ID when doing a global DNS request and our index 208 * be our message ID when doing a global DNS request and our index
145 * into the 'requests' array. 209 * into the 'requests' array.
@@ -186,11 +250,23 @@ struct TunnelState
186 char *reply; 250 char *reply;
187 251
188 /** 252 /**
253 * Socket we are using to transmit this request (must match if we receive
254 * a response). Must NOT be freed as part of this request record (as it
255 * might be shared with other requests).
256 */
257 struct GNUNET_NETWORK_Handle *dnsout;
258
259 /**
189 * Address we sent the DNS request to. 260 * Address we sent the DNS request to.
190 */ 261 */
191 struct sockaddr_storage addr; 262 struct sockaddr_storage addr;
192 263
193 /** 264 /**
265 * When should this request time out?
266 */
267 struct GNUNET_TIME_Absolute timeout;
268
269 /**
194 * Number of bytes in 'addr'. 270 * Number of bytes in 'addr'.
195 */ 271 */
196 socklen_t addrlen; 272 socklen_t addrlen;
@@ -213,28 +289,6 @@ struct TunnelState
213 289
214 290
215/** 291/**
216 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
217 * sent through gnunet. The port of this socket will not be hijacked.
218 */
219static struct GNUNET_NETWORK_Handle *dnsout4;
220
221/**
222 * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
223 * sent through gnunet. The port of this socket will not be hijacked.
224 */
225static struct GNUNET_NETWORK_Handle *dnsout6;
226
227/**
228 * Task for reading from dnsout4.
229 */
230static GNUNET_SCHEDULER_TaskIdentifier read4_task;
231
232/**
233 * Task for reading from dnsout6.
234 */
235static GNUNET_SCHEDULER_TaskIdentifier read6_task;
236
237/**
238 * The configuration to use 292 * The configuration to use
239 */ 293 */
240static const struct GNUNET_CONFIGURATION_Handle *cfg; 294static const struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -280,6 +334,11 @@ static struct RequestRecord requests[UINT16_MAX + 1];
280static struct TunnelState *tunnels[UINT16_MAX + 1]; 334static struct TunnelState *tunnels[UINT16_MAX + 1];
281 335
282/** 336/**
337 * Array of all open sockets for DNS requests.
338 */
339static struct RequestSocket sockets[DNS_SOCKET_MAX];
340
341/**
283 * Generator for unique request IDs. 342 * Generator for unique request IDs.
284 */ 343 */
285static uint64_t request_id_gen; 344static uint64_t request_id_gen;
@@ -296,10 +355,31 @@ static char *dns_exit;
296 */ 355 */
297static struct GNUNET_MESH_Handle *mesh; 356static struct GNUNET_MESH_Handle *mesh;
298 357
358
299/** 359/**
300 * Number of active DNS requests. 360 * We're done with a RequestSocket, close it for now.
361 *
362 * @param rr request to clean up
301 */ 363 */
302static unsigned int dns_active; 364static void
365cleanup_rs (struct RequestSocket *rs)
366{
367 if (NULL != rs->dnsout4)
368 {
369 GNUNET_NETWORK_socket_close (rs->dnsout4);
370 rs->dnsout4 = NULL;
371 }
372 if (NULL != rs->dnsout6)
373 {
374 GNUNET_NETWORK_socket_close (rs->dnsout6);
375 rs->dnsout6 = NULL;
376 }
377 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
378 {
379 GNUNET_SCHEDULER_cancel (rs->read_task);
380 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
381 }
382}
303 383
304 384
305/** 385/**
@@ -335,27 +415,7 @@ cleanup_task (void *cls GNUNET_UNUSED,
335 hijacker = NULL; 415 hijacker = NULL;
336 for (i=0;i<7;i++) 416 for (i=0;i<7;i++)
337 GNUNET_free_non_null (helper_argv[i]); 417 GNUNET_free_non_null (helper_argv[i]);
338 if (NULL != dnsout4) 418 for (i=0;i<=UINT16_MAX;i++)
339 {
340 GNUNET_NETWORK_socket_close (dnsout4);
341 dnsout4 = NULL;
342 }
343 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
344 {
345 GNUNET_SCHEDULER_cancel (read4_task);
346 read4_task = GNUNET_SCHEDULER_NO_TASK;
347 }
348 if (NULL != dnsout6)
349 {
350 GNUNET_NETWORK_socket_close (dnsout6);
351 dnsout6 = NULL;
352 }
353 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
354 {
355 GNUNET_SCHEDULER_cancel (read6_task);
356 read6_task = GNUNET_SCHEDULER_NO_TASK;
357 }
358 for (i=0;i<65536;i++)
359 cleanup_rr (&requests[i]); 419 cleanup_rr (&requests[i]);
360 GNUNET_SERVER_notification_context_destroy (nc); 420 GNUNET_SERVER_notification_context_destroy (nc);
361 nc = NULL; 421 nc = NULL;
@@ -373,6 +433,53 @@ cleanup_task (void *cls GNUNET_UNUSED,
373 433
374 434
375/** 435/**
436 * Open source port for sending DNS requests
437 *
438 * @param af AF_INET or AF_INET6
439 * @return GNUNET_OK on success
440 */
441static struct GNUNET_NETWORK_Handle *
442open_socket (int af)
443{
444 struct sockaddr_in a4;
445 struct sockaddr_in6 a6;
446 struct sockaddr *sa;
447 socklen_t alen;
448 struct GNUNET_NETWORK_Handle *ret;
449
450 ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
451 if (NULL == ret)
452 return NULL;
453 switch (af)
454 {
455 case AF_INET:
456 memset (&a4, 0, alen = sizeof (struct sockaddr_in));
457 sa = (struct sockaddr *) &a4;
458 break;
459 case AF_INET6:
460 memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
461 sa = (struct sockaddr *) &a6;
462 break;
463 default:
464 GNUNET_break (0);
465 return NULL;
466 }
467 sa->sa_family = af;
468 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
469 sa,
470 alen))
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473 _("Could not bind to any port: %s\n"),
474 STRERROR (errno));
475 GNUNET_NETWORK_socket_close (ret);
476 return NULL;
477 }
478 return ret;
479}
480
481
482/**
376 * We're done with some request, finish processing. 483 * We're done with some request, finish processing.
377 * 484 *
378 * @param rr request send to the network or just clean up. 485 * @param rr request send to the network or just clean up.
@@ -559,10 +666,70 @@ send_request_to_client (struct RequestRecord *rr,
559 666
560 667
561/** 668/**
562 * Try to change the source ports we are bound to. 669 * Read a DNS response from the (unhindered) UDP-Socket
670 *
671 * @param cls socket to read from
672 * @param tc scheduler context (must be shutdown or read ready)
563 */ 673 */
564static void 674static void
565change_source_ports (); 675read_response (void *cls,
676 const struct GNUNET_SCHEDULER_TaskContext *tc);
677
678
679/**
680 * Get a socket of the specified address family to send out a
681 * UDP DNS request to the Internet.
682 *
683 * @param af desired address family
684 * @return NULL on error (given AF not "supported")
685 */
686static struct GNUNET_NETWORK_Handle *
687get_request_socket (int af)
688{
689 struct RequestSocket *rs;
690 struct GNUNET_NETWORK_FDSet *rset;
691 static struct GNUNET_NETWORK_Handle *ret;
692
693 rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
694 DNS_SOCKET_MAX)];
695 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
696 switch (af)
697 {
698 case AF_INET:
699 if (NULL == rs->dnsout4)
700 rs->dnsout4 = open_socket (AF_INET);
701 ret = rs->dnsout4;
702 break;
703 case AF_INET6:
704 if (NULL == rs->dnsout6)
705 rs->dnsout6 = open_socket (AF_INET6);
706 ret = rs->dnsout6;
707 break;
708 default:
709 return NULL;
710 }
711 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
712 {
713 GNUNET_SCHEDULER_cancel (rs->read_task);
714 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
715 }
716 if ( (NULL == rs->dnsout4) &&
717 (NULL == rs->dnsout6) )
718 return NULL;
719 rset = GNUNET_NETWORK_fdset_create ();
720 if (NULL != rs->dnsout4)
721 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
722 if (NULL != rs->dnsout6)
723 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
724 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
725 GNUNET_SCHEDULER_NO_TASK,
726 REQUEST_TIMEOUT,
727 rset,
728 NULL,
729 &read_response, rs);
730 GNUNET_NETWORK_fdset_destroy (rset);
731 return ret;
732}
566 733
567 734
568/** 735/**
@@ -577,7 +744,6 @@ next_phase (struct RequestRecord *rr)
577 struct ClientRecord *cr; 744 struct ClientRecord *cr;
578 int nz; 745 int nz;
579 unsigned int j; 746 unsigned int j;
580 struct GNUNET_NETWORK_Handle *dnsout;
581 socklen_t salen; 747 socklen_t salen;
582 748
583 if (rr->phase == RP_DROP) 749 if (rr->phase == RP_DROP)
@@ -625,41 +791,36 @@ next_phase (struct RequestRecord *rr)
625 next_phase (rr); 791 next_phase (rr);
626 return; 792 return;
627 case RP_QUERY: 793 case RP_QUERY:
628 rr->phase = RP_INTERNET_DNS;
629 dns_active++;
630 switch (rr->dst_addr.ss_family) 794 switch (rr->dst_addr.ss_family)
631 { 795 {
632 case AF_INET: 796 case AF_INET:
633 dnsout = dnsout4; 797 salen = sizeof (struct sockaddr_in);
634 salen = sizeof (struct GNUNET_TUN_IPv4Header);
635 break; 798 break;
636 case AF_INET6: 799 case AF_INET6:
637 dnsout = dnsout6; 800 salen = sizeof (struct sockaddr_in6);
638 salen = sizeof (struct GNUNET_TUN_IPv6Header);
639 break; 801 break;
640 default: 802 default:
641 GNUNET_break (0); 803 GNUNET_assert (0);
642 cleanup_rr (rr);
643 return;
644 } 804 }
645 if (NULL == dnsout) 805
806 rr->phase = RP_INTERNET_DNS;
807 rr->dnsout = get_request_socket (rr->dst_addr.ss_family);
808 if (NULL == rr->dnsout)
646 { 809 {
647 GNUNET_STATISTICS_update (stats, 810 GNUNET_STATISTICS_update (stats,
648 gettext_noop ("# DNS exit failed (address family not supported)"), 811 gettext_noop ("# DNS exit failed (failed to open socket)"),
649 1, GNUNET_NO); 812 1, GNUNET_NO);
650 cleanup_rr (rr); 813 cleanup_rr (rr);
651 return; 814 return;
652 } 815 }
653 GNUNET_NETWORK_socket_sendto (dnsout, 816 GNUNET_NETWORK_socket_sendto (rr->dnsout,
654 rr->payload, 817 rr->payload,
655 rr->payload_length, 818 rr->payload_length,
656 (struct sockaddr*) &rr->dst_addr, 819 (struct sockaddr*) &rr->dst_addr,
657 salen); 820 salen);
821 rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
658 return; 822 return;
659 case RP_INTERNET_DNS: 823 case RP_INTERNET_DNS:
660 dns_active--;
661 if (0 == dns_active)
662 change_source_ports ();
663 rr->phase = RP_MODIFY; 824 rr->phase = RP_MODIFY;
664 for (cr = clients_head; NULL != cr; cr = cr->next) 825 for (cr = clients_head; NULL != cr; cr = cr->next)
665 { 826 {
@@ -785,85 +946,65 @@ transmit_reply_to_mesh (void *cls,
785 946
786 947
787/** 948/**
788 * Read a DNS response from the (unhindered) UDP-Socket 949 * Actually do the reading of a DNS packet from our UDP socket and see
950 * if we have a valid, matching, pending request.
789 * 951 *
790 * @param cls socket to read from 952 * @param dnsout socket to read from
791 * @param tc scheduler context (must be shutdown or read ready) 953 * @param GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
792 */ 954 */
793static void 955static int
794read_response (void *cls, 956do_dns_read (struct GNUNET_NETWORK_Handle *dnsout)
795 const struct GNUNET_SCHEDULER_TaskContext *tc)
796{ 957{
797 struct GNUNET_NETWORK_Handle *dnsout = cls; 958 struct sockaddr_storage addr;
798 struct sockaddr_in addr4;
799 struct sockaddr_in6 addr6;
800 struct sockaddr *addr;
801 struct GNUNET_TUN_DnsHeader *dns;
802 socklen_t addrlen; 959 socklen_t addrlen;
960 struct GNUNET_TUN_DnsHeader *dns;
803 struct RequestRecord *rr; 961 struct RequestRecord *rr;
804 struct TunnelState *ts; 962 struct TunnelState *ts;
805 ssize_t r; 963 ssize_t r;
806 int len; 964 int len;
807 965
808 if (dnsout == dnsout4)
809 {
810 addrlen = sizeof (struct sockaddr_in);
811 addr = (struct sockaddr* ) &addr4;
812 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
813 dnsout,
814 &read_response,
815 dnsout);
816 }
817 else
818 {
819 addrlen = sizeof (struct sockaddr_in6);
820 addr = (struct sockaddr* ) &addr6;
821 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
822 dnsout,
823 &read_response,
824 dnsout);
825 }
826 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
827 return;
828
829#ifndef MINGW 966#ifndef MINGW
830 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) 967 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
831 { 968 {
832 /* conservative choice: */ 969 /* conservative choice: */
833 len = 65536; 970 len = UINT16_MAX;
834 } 971 }
835#else 972#else
836 /* port the code above? */ 973 /* port the code above? */
837 len = 65536; 974 len = UINT16_MAX;
838#endif 975#endif
839 976
840 { 977 {
841 unsigned char buf[len]; 978 unsigned char buf[len];
842 979
843 memset (addr, 0, addrlen); 980 addrlen = sizeof (addr);
981 memset (&addr, 0, sizeof (addr));
844 r = GNUNET_NETWORK_socket_recvfrom (dnsout, 982 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
845 buf, sizeof (buf), 983 buf, sizeof (buf),
846 addr, &addrlen); 984 (struct sockaddr*) &addr, &addrlen);
847 if (-1 == r) 985 if (-1 == r)
848 { 986 {
849 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); 987 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
850 return; 988 GNUNET_NETWORK_socket_close (dnsout);
989 return GNUNET_SYSERR;
851 } 990 }
852 if (sizeof (struct GNUNET_TUN_DnsHeader) > r) 991 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
853 { 992 {
854 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 993 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
855 _("Received DNS response that is too small (%u bytes)"), 994 _("Received DNS response that is too small (%u bytes)"),
856 r); 995 r);
857 return; 996 return GNUNET_NO;
858 } 997 }
859 dns = (struct GNUNET_TUN_DnsHeader *) buf; 998 dns = (struct GNUNET_TUN_DnsHeader *) buf;
860 /* Handle case that this is a reply to a request from a MESH DNS tunnel */ 999 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
861 ts = tunnels[dns->id]; 1000 ts = tunnels[dns->id];
862 if ( (NULL == ts) || 1001 if ( (NULL == ts) ||
1002 (ts->dnsout != dnsout) ||
863 (addrlen != ts->addrlen) || 1003 (addrlen != ts->addrlen) ||
864 (0 != memcmp (&ts->addr, 1004 (0 != memcmp (&ts->addr,
865 addr, 1005 &addr,
866 addrlen)) ) 1006 addrlen)) ||
1007 (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) )
867 ts = NULL; /* DNS responder address missmatch */ 1008 ts = NULL; /* DNS responder address missmatch */
868 if (NULL != ts) 1009 if (NULL != ts)
869 { 1010 {
@@ -884,7 +1025,12 @@ read_response (void *cls,
884 } 1025 }
885 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */ 1026 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
886 rr = &requests[dns->id]; 1027 rr = &requests[dns->id];
887 if (rr->phase != RP_INTERNET_DNS) 1028 if ( (rr->phase != RP_INTERNET_DNS) ||
1029 (rr->dnsout != dnsout) ||
1030 (0 != memcmp (&rr->dst_addr,
1031 &addr,
1032 addrlen)) ||
1033 (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) )
888 { 1034 {
889 if (NULL == ts) 1035 if (NULL == ts)
890 { 1036 {
@@ -893,7 +1039,7 @@ read_response (void *cls,
893 gettext_noop ("# External DNS response discarded (no matching request)"), 1039 gettext_noop ("# External DNS response discarded (no matching request)"),
894 1, GNUNET_NO); 1040 1, GNUNET_NO);
895 } 1041 }
896 return; 1042 return GNUNET_NO;
897 } 1043 }
898 GNUNET_free_non_null (rr->payload); 1044 GNUNET_free_non_null (rr->payload);
899 rr->payload = GNUNET_malloc (r); 1045 rr->payload = GNUNET_malloc (r);
@@ -901,131 +1047,53 @@ read_response (void *cls,
901 rr->payload_length = r; 1047 rr->payload_length = r;
902 next_phase (rr); 1048 next_phase (rr);
903 } 1049 }
904}
905
906
907/**
908 * Open source port for sending DNS request on IPv4.
909 *
910 * @return GNUNET_OK on success
911 */
912static int
913open_port4 ()
914{
915 struct sockaddr_in addr;
916
917 dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
918 if (dnsout4 == NULL)
919 return GNUNET_SYSERR;
920
921 memset (&addr, 0, sizeof (struct sockaddr_in));
922 addr.sin_family = AF_INET;
923 int err = GNUNET_NETWORK_socket_bind (dnsout4,
924 (struct sockaddr *) &addr,
925 sizeof (struct sockaddr_in));
926
927 if (err != GNUNET_OK)
928 {
929 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930 _("Could not bind to any port: %s\n"),
931 STRERROR (errno));
932 GNUNET_NETWORK_socket_close (dnsout4);
933 dnsout4 = NULL;
934 return GNUNET_SYSERR;
935 }
936 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
937 dnsout4,
938 &read_response, dnsout4);
939 return GNUNET_OK; 1050 return GNUNET_OK;
940} 1051}
941 1052
942 1053
943/** 1054/**
944 * Open source port for sending DNS request on IPv6. Should be 1055 * Read a DNS response from the (unhindered) UDP-Socket
945 * called AFTER open_port4.
946 * 1056 *
947 * @return GNUNET_OK on success 1057 * @param cls socket to read from
948 */ 1058 * @param tc scheduler context (must be shutdown or read ready)
949static int
950open_port6 ()
951{
952 struct sockaddr_in6 addr;
953
954 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
955 if (dnsout6 == NULL)
956 {
957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
958 _("Could not create IPv6 socket: %s\n"),
959 STRERROR (errno));
960 return GNUNET_SYSERR;
961 }
962 memset (&addr, 0, sizeof (struct sockaddr_in6));
963 addr.sin6_family = AF_INET6;
964 int err = GNUNET_NETWORK_socket_bind (dnsout6,
965 (struct sockaddr *) &addr,
966 sizeof (struct sockaddr_in6));
967
968 if (err != GNUNET_OK)
969 {
970 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
971 _("Could not bind: %s\n"),
972 STRERROR (errno));
973 GNUNET_NETWORK_socket_close (dnsout6);
974 dnsout6 = NULL;
975 return GNUNET_SYSERR;
976 }
977 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
978 dnsout6,
979 &read_response, dnsout6);
980 return GNUNET_YES;
981}
982
983
984/**
985 * Try to change the source ports we are bound to.
986 */ 1059 */
987static void 1060static void
988change_source_ports () 1061read_response (void *cls,
1062 const struct GNUNET_SCHEDULER_TaskContext *tc)
989{ 1063{
990 struct GNUNET_NETWORK_Handle *old4; 1064 struct RequestSocket *rs = cls;
991 struct GNUNET_NETWORK_Handle *old6; 1065 struct GNUNET_NETWORK_FDSet *rset;
992 1066
993 if (GNUNET_SCHEDULER_NO_TASK != read4_task) 1067 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
994 { 1068 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
995 GNUNET_SCHEDULER_cancel (read4_task);
996 read4_task = GNUNET_SCHEDULER_NO_TASK;
997 }
998 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
999 {
1000 GNUNET_SCHEDULER_cancel (read6_task);
1001 read6_task = GNUNET_SCHEDULER_NO_TASK;
1002 }
1003 old4 = dnsout4;
1004 if (GNUNET_OK != open_port4 ())
1005 {
1006 dnsout4 = old4;
1007 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1008 dnsout4,
1009 &read_response, dnsout4);
1010 }
1011 else
1012 {
1013 if (NULL != old4)
1014 GNUNET_NETWORK_socket_close (old4);
1015 }
1016 old6 = dnsout6;
1017 if (GNUNET_OK != open_port6 ())
1018 {
1019 dnsout6 = old6;
1020 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1021 dnsout6,
1022 &read_response, dnsout6);
1023 }
1024 else
1025 { 1069 {
1026 if (NULL != old6) 1070 /* timeout or shutdown */
1027 GNUNET_NETWORK_socket_close (old6); 1071 cleanup_rs (rs);
1072 return;
1028 } 1073 }
1074 /* read and process ready sockets */
1075 if ((NULL != rs->dnsout4) &&
1076 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
1077 (GNUNET_SYSERR == do_dns_read (rs->dnsout4)))
1078 rs->dnsout4 = NULL;
1079 if ((NULL != rs->dnsout6) &&
1080 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
1081 (GNUNET_SYSERR == do_dns_read (rs->dnsout6)))
1082 rs->dnsout6 = NULL;
1083
1084 /* re-schedule read task */
1085 rset = GNUNET_NETWORK_fdset_create ();
1086 if (NULL != rs->dnsout4)
1087 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
1088 if (NULL != rs->dnsout6)
1089 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
1090 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1091 GNUNET_SCHEDULER_NO_TASK,
1092 GNUNET_TIME_absolute_get_remaining (rs->timeout),
1093 rset,
1094 NULL,
1095 &read_response, rs);
1096 GNUNET_NETWORK_fdset_destroy (rset);
1029} 1097}
1030 1098
1031 1099
@@ -1234,12 +1302,6 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1234 1302
1235 /* clean up from previous request */ 1303 /* clean up from previous request */
1236 GNUNET_free_non_null (rr->payload); 1304 GNUNET_free_non_null (rr->payload);
1237 if (RP_INTERNET_DNS == rr->phase)
1238 {
1239 dns_active--;
1240 if (0 == dns_active)
1241 change_source_ports ();
1242 }
1243 rr->payload = NULL; 1305 rr->payload = NULL;
1244 GNUNET_array_grow (rr->client_wait_list, 1306 GNUNET_array_grow (rr->client_wait_list,
1245 rr->client_wait_list_length, 1307 rr->client_wait_list_length,
@@ -1331,7 +1393,6 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1331 struct sockaddr_in6 v6; 1393 struct sockaddr_in6 v6;
1332 struct sockaddr *so; 1394 struct sockaddr *so;
1333 socklen_t salen; 1395 socklen_t salen;
1334 struct GNUNET_NETWORK_Handle *dnsout;
1335 1396
1336 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) 1397 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1337 { 1398 {
@@ -1343,7 +1404,7 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1343 if (tunnels[ts->my_id] == ts) 1404 if (tunnels[ts->my_id] == ts)
1344 tunnels[ts->my_id] = NULL; 1405 tunnels[ts->my_id] = NULL;
1345 ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1406 ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1346 65536); 1407 UINT16_MAX + 1);
1347 tunnels[ts->my_id] = ts; 1408 tunnels[ts->my_id] = ts;
1348 memcpy (buf, dns, dlen); 1409 memcpy (buf, dns, dlen);
1349 dout = (struct GNUNET_TUN_DnsHeader*) buf; 1410 dout = (struct GNUNET_TUN_DnsHeader*) buf;
@@ -1351,7 +1412,6 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1351 1412
1352 memset (&v4, 0, sizeof (v4)); 1413 memset (&v4, 0, sizeof (v4));
1353 memset (&v6, 0, sizeof (v6)); 1414 memset (&v6, 0, sizeof (v6));
1354 dnsout = NULL;
1355 if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr)) 1415 if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr))
1356 { 1416 {
1357 salen = sizeof (v4); 1417 salen = sizeof (v4);
@@ -1361,7 +1421,7 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1361 v4.sin_len = (u_char) salen; 1421 v4.sin_len = (u_char) salen;
1362#endif 1422#endif
1363 so = (struct sockaddr *) &v4; 1423 so = (struct sockaddr *) &v4;
1364 dnsout = dnsout4; 1424 ts->dnsout = get_request_socket (AF_INET);
1365 } 1425 }
1366 if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr)) 1426 if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
1367 { 1427 {
@@ -1372,9 +1432,9 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1372 v6.sin6_len = (u_char) salen; 1432 v6.sin6_len = (u_char) salen;
1373#endif 1433#endif
1374 so = (struct sockaddr *) &v6; 1434 so = (struct sockaddr *) &v6;
1375 dnsout = dnsout6; 1435 ts->dnsout = get_request_socket (AF_INET6);
1376 } 1436 }
1377 if (NULL == dnsout) 1437 if (NULL == ts->dnsout)
1378 { 1438 {
1379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1439 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1380 _("Configured DNS exit `%s' is not working / valid.\n"), 1440 _("Configured DNS exit `%s' is not working / valid.\n"),
@@ -1385,8 +1445,9 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1385 so, 1445 so,
1386 salen); 1446 salen);
1387 ts->addrlen = salen; 1447 ts->addrlen = salen;
1388 GNUNET_NETWORK_socket_sendto (dnsout, 1448 GNUNET_NETWORK_socket_sendto (ts->dnsout,
1389 buf, dlen, so, salen); 1449 buf, dlen, so, salen);
1450 ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
1390 return GNUNET_OK; 1451 return GNUNET_OK;
1391} 1452}
1392 1453
@@ -1464,27 +1525,24 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
1464 char *ipv4mask; 1525 char *ipv4mask;
1465 char *ipv6addr; 1526 char *ipv6addr;
1466 char *ipv6prefix; 1527 char *ipv6prefix;
1528 struct in_addr dns_exit4;
1529 struct in6_addr dns_exit6;
1467 1530
1468 cfg = cfg_; 1531 cfg = cfg_;
1469 stats = GNUNET_STATISTICS_create ("dns", cfg); 1532 stats = GNUNET_STATISTICS_create ("dns", cfg);
1470 nc = GNUNET_SERVER_notification_context_create (server, 1); 1533 nc = GNUNET_SERVER_notification_context_create (server, 1);
1471 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, 1534 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1472 cls); 1535 cls);
1473 (void) GNUNET_CONFIGURATION_get_value_string (cfg, "dns", 1536 if ( (GNUNET_YES ==
1474 "DNS_EXIT", 1537 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) &&
1475 &dns_exit); 1538 ( (GNUNET_OK !=
1476 if (GNUNET_YES == 1539 GNUNET_CONFIGURATION_get_value_string (cfg, "dns",
1477 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) 1540 "DNS_EXIT",
1478 { 1541 &dns_exit)) ||
1479 if ( (GNUNET_OK != open_port4 ()) && 1542 ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1480 (GNUNET_OK != open_port6 ()) ) 1543 (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1481 { 1544 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1545 _("Configured to provide DNS exit, but no valid DNS server configured!\n"));
1483 _("Failed to open any port to provide DNS exit\n"));
1484 GNUNET_SCHEDULER_shutdown ();
1485 return;
1486 }
1487 }
1488 1546
1489 helper_argv[0] = GNUNET_strdup ("gnunet-dns"); 1547 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1490 if (GNUNET_SYSERR == 1548 if (GNUNET_SYSERR ==