aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorgrothoff <grothoff@140774ce-b5e7-0310-ab8b-a85725594a96>2012-08-21 06:01:06 +0000
committergrothoff <grothoff@140774ce-b5e7-0310-ab8b-a85725594a96>2012-08-21 06:01:06 +0000
commitfed37bbf3c6c469f197e84a57c39d9567fe58591 (patch)
tree71a692e8a19b10900dc2360173b1e8b06d1db70f /src/dns
parent3985e02f3518892aac5d1a90b71c6dd61e0ee4bd (diff)
refactoring dns service to take stub code into separate library for use in gns2dns proxy
git-svn-id: https://gnunet.org/svn/gnunet@23331 140774ce-b5e7-0310-ab8b-a85725594a96
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/Makefile.am10
-rw-r--r--src/dns/dnsstub.c520
-rw-r--r--src/dns/gnunet-service-dns.c468
3 files changed, 606 insertions, 392 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index 8a102c414b..aca8ea25cb 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -25,6 +25,7 @@ endif
lib_LTLIBRARIES = \
libgnunetdnsparser.la \
+ libgnunetdnsstub.la \
libgnunetdns.la
bin_PROGRAMS = \
@@ -70,6 +71,7 @@ gnunet_dns_redirector_DEPENDENCIES = \
gnunet_service_dns_SOURCES = \
gnunet-service-dns.c
gnunet_service_dns_LDADD = \
+ $(top_builddir)/src/dns/libgnunetdnsstub.la \
$(top_builddir)/src/tun/libgnunettun.la \
$(top_builddir)/src/mesh/libgnunetmesh.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
@@ -84,6 +86,14 @@ libgnunetdnsparser_la_LDFLAGS = \
$(GN_LIB_LDFLAGS) \
-version-info 0:0:0
+libgnunetdnsstub_la_SOURCES = \
+ dnsstub.c
+libgnunetdnsstub_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIB)
+libgnunetdnsstub_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) \
+ -version-info 0:0:0
+
libgnunetdns_la_SOURCES = \
dns_api.c dns.h
libgnunetdns_la_LIBADD = \
diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c
new file mode 100644
index 0000000000..383b1d6999
--- /dev/null
+++ b/src/dns/dnsstub.c
@@ -0,0 +1,520 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file dns/dnsstub.c
+ * @brief DNS stub resolver which sends DNS requests to an actual resolver
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dnsstub_lib.h"
+
+/**
+ * Timeout for an external (Internet-DNS) DNS resolution
+ */
+#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+/**
+ * How many DNS sockets do we open at most at the same time?
+ * (technical socket maximum is this number x2 for IPv4+IPv6)
+ */
+#define DNS_SOCKET_MAX 128
+
+
+/**
+ * UDP socket we are using for sending DNS requests to the Internet.
+ */
+struct GNUNET_DNSSTUB_RequestSocket
+{
+
+ /**
+ * UDP socket we use for this request for IPv4
+ */
+ struct GNUNET_NETWORK_Handle *dnsout4;
+
+ /**
+ * UDP socket we use for this request for IPv6
+ */
+ struct GNUNET_NETWORK_Handle *dnsout6;
+
+ /**
+ * Function to call with result.
+ */
+ GNUNET_DNSSTUB_ResultCallback rc;
+
+ /**
+ * Closure for 'rc'.
+ */
+ void *rc_cls;
+
+ /**
+ * Task for reading from dnsout4 and dnsout6.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier read_task;
+
+ /**
+ * When should this request time out?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Address we sent the DNS request to.
+ */
+ struct sockaddr_storage addr;
+
+ /**
+ * Number of bytes in 'addr'.
+ */
+ socklen_t addrlen;
+
+};
+
+
+struct GNUNET_DNSSTUB_Context
+{
+
+ /**
+ * Array of all open sockets for DNS requests.
+ */
+ struct GNUNET_DNSSTUB_RequestSocket sockets[DNS_SOCKET_MAX];
+
+ /**
+ * IP address to use for the DNS server if we are a DNS exit service
+ * (for VPN via mesh); otherwise NULL.
+ */
+ char *dns_exit;
+};
+
+
+
+/**
+ * We're done with a GNUNET_DNSSTUB_RequestSocket, close it for now.
+ *
+ * @param rs request socket to clean up
+ */
+static void
+cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
+{
+ if (NULL != rs->dnsout4)
+ {
+ GNUNET_NETWORK_socket_close (rs->dnsout4);
+ rs->dnsout4 = NULL;
+ }
+ if (NULL != rs->dnsout6)
+ {
+ GNUNET_NETWORK_socket_close (rs->dnsout6);
+ rs->dnsout6 = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
+ {
+ GNUNET_SCHEDULER_cancel (rs->read_task);
+ rs->read_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+}
+
+
+/**
+ * Open source port for sending DNS requests
+ *
+ * @param af AF_INET or AF_INET6
+ * @return GNUNET_OK on success
+ */
+static struct GNUNET_NETWORK_Handle *
+open_socket (int af)
+{
+ struct sockaddr_in a4;
+ struct sockaddr_in6 a6;
+ struct sockaddr *sa;
+ socklen_t alen;
+ struct GNUNET_NETWORK_Handle *ret;
+
+ ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
+ if (NULL == ret)
+ return NULL;
+ switch (af)
+ {
+ case AF_INET:
+ memset (&a4, 0, alen = sizeof (struct sockaddr_in));
+ sa = (struct sockaddr *) &a4;
+ break;
+ case AF_INET6:
+ memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
+ sa = (struct sockaddr *) &a6;
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_NETWORK_socket_close (ret);
+ return NULL;
+ }
+ sa->sa_family = af;
+ if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
+ sa,
+ alen))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not bind to any port: %s\n"),
+ STRERROR (errno));
+ GNUNET_NETWORK_socket_close (ret);
+ return NULL;
+ }
+ return ret;
+}
+
+
+/**
+ * Read a DNS response from the (unhindered) UDP-Socket
+ *
+ * @param cls socket to read from
+ * @param tc scheduler context (must be shutdown or read ready)
+ */
+static void
+read_response (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Get a socket of the specified address family to send out a
+ * UDP DNS request to the Internet.
+ *
+ * @param af desired address family
+ * @return NULL on error (given AF not "supported")
+ */
+static struct GNUNET_DNSSTUB_RequestSocket *
+get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
+ int af)
+{
+ struct GNUNET_DNSSTUB_RequestSocket *rs;
+ struct GNUNET_NETWORK_FDSet *rset;
+
+ rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ DNS_SOCKET_MAX)];
+ rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
+ switch (af)
+ {
+ case AF_INET:
+ if (NULL == rs->dnsout4)
+ rs->dnsout4 = open_socket (AF_INET);
+ break;
+ case AF_INET6:
+ if (NULL == rs->dnsout6)
+ rs->dnsout6 = open_socket (AF_INET6);
+ break;
+ default:
+ return NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
+ {
+ GNUNET_SCHEDULER_cancel (rs->read_task);
+ rs->read_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if ( (NULL == rs->dnsout4) &&
+ (NULL == rs->dnsout6) )
+ return NULL;
+ rset = GNUNET_NETWORK_fdset_create ();
+ if (NULL != rs->dnsout4)
+ GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
+ if (NULL != rs->dnsout6)
+ GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
+ rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ REQUEST_TIMEOUT,
+ rset,
+ NULL,
+ &read_response, rs);
+ GNUNET_NETWORK_fdset_destroy (rset);
+ return rs;
+}
+
+
+/**
+ * Perform DNS resolution.
+ *
+ * @param ctx stub resolver to use
+ * @param af address family to use
+ * @param request DNS request to transmit
+ * @param request_len number of bytes in msg
+ * @param rc function to call with result
+ * @param rc_cls closure for 'rc'
+ * @return socket used for the request, NULL on error
+ */
+struct GNUNET_DNSSTUB_RequestSocket *
+GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
+ const struct sockaddr *sa,
+ socklen_t sa_len,
+ const void *request,
+ size_t request_len,
+ GNUNET_DNSSTUB_ResultCallback rc,
+ void *rc_cls)
+{
+ struct GNUNET_DNSSTUB_RequestSocket *rs;
+ struct GNUNET_NETWORK_Handle *ret;
+ int af;
+
+ af = sa->sa_family;
+ if (NULL == (rs = get_request_socket (ctx, af)))
+ return NULL;
+ if (NULL != rs->dnsout4)
+ ret = rs->dnsout4;
+ else
+ ret = rs->dnsout6;
+ GNUNET_assert (NULL != ret);
+ rs->rc = rc;
+ rs->rc_cls = rc_cls;
+ GNUNET_NETWORK_socket_sendto (ret,
+ request,
+ request_len,
+ sa,
+ sa_len);
+ return rs;
+}
+
+
+/**
+ * Perform DNS resolution using our default IP from init.
+ *
+ * @param ctx stub resolver to use
+ * @param request DNS request to transmit
+ * @param request_len number of bytes in msg
+ * @param rc function to call with result
+ * @param rc_cls closure for 'rc'
+ * @return socket used for the request, NULL on error
+ */
+struct GNUNET_DNSSTUB_RequestSocket *
+GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
+ const void *request,
+ size_t request_len,
+ GNUNET_DNSSTUB_ResultCallback rc,
+ void *rc_cls)
+{
+ int af;
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ struct sockaddr *so;
+ socklen_t salen;
+ struct GNUNET_NETWORK_Handle *dnsout;
+ struct GNUNET_DNSSTUB_RequestSocket *rs;
+
+ memset (&v4, 0, sizeof (v4));
+ memset (&v6, 0, sizeof (v6));
+ if (1 == inet_pton (AF_INET, ctx->dns_exit, &v4.sin_addr))
+ {
+ salen = sizeof (v4);
+ v4.sin_family = AF_INET;
+ v4.sin_port = htons (53);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v4.sin_len = (u_char) salen;
+#endif
+ so = (struct sockaddr *) &v4;
+ af = AF_INET;
+ }
+ else if (1 == inet_pton (AF_INET6, ctx->dns_exit, &v6.sin6_addr))
+ {
+ salen = sizeof (v6);
+ v6.sin6_family = AF_INET6;
+ v6.sin6_port = htons (53);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v6.sin6_len = (u_char) salen;
+#endif
+ so = (struct sockaddr *) &v6;
+ af = AF_INET6;
+ }
+ else
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (NULL == (rs = get_request_socket (ctx, af)))
+ return NULL;
+ if (NULL != rs->dnsout4)
+ dnsout = rs->dnsout4;
+ else
+ dnsout = rs->dnsout6;
+ if (NULL == dnsout)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Configured DNS exit `%s' is not working / valid.\n"),
+ ctx->dns_exit);
+ return NULL;
+ }
+ memcpy (&rs->addr,
+ so,
+ salen);
+ rs->addrlen = salen;
+ GNUNET_NETWORK_socket_sendto (dnsout,
+ request,
+ request_len, so, salen);
+ rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
+
+ return rs;
+
+}
+
+
+/**
+ * Actually do the reading of a DNS packet from our UDP socket and see
+ * if we have a valid, matching, pending request.
+ *
+ * @param rs request socket with callback details
+ * @param dnsout socket to read from
+ * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
+ */
+static int
+do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
+ struct GNUNET_NETWORK_Handle *dnsout)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ struct GNUNET_TUN_DnsHeader *dns;
+ ssize_t r;
+ int len;
+
+#ifndef MINGW
+ if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
+ {
+ /* conservative choice: */
+ len = UINT16_MAX;
+ }
+#else
+ /* port the code above? */
+ len = UINT16_MAX;
+#endif
+
+ {
+ unsigned char buf[len] GNUNET_ALIGN;
+
+ addrlen = sizeof (addr);
+ memset (&addr, 0, sizeof (addr));
+ r = GNUNET_NETWORK_socket_recvfrom (dnsout,
+ buf, sizeof (buf),
+ (struct sockaddr*) &addr, &addrlen);
+ if (-1 == r)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
+ GNUNET_NETWORK_socket_close (dnsout);
+ return GNUNET_SYSERR;
+ }
+ if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Received DNS response that is too small (%u bytes)"),
+ r);
+ return GNUNET_NO;
+ }
+ dns = (struct GNUNET_TUN_DnsHeader *) buf;
+ if ( (addrlen != rs->addrlen) ||
+ (0 != memcmp (&rs->addr,
+ &addr,
+ addrlen)) ||
+ (0 == GNUNET_TIME_absolute_get_remaining (rs->timeout).rel_value) )
+ return GNUNET_NO;
+ rs->rc (rs->rc_cls,
+ rs,
+ dns,
+ r);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Read a DNS response from the (unhindered) UDP-Socket
+ *
+ * @param cls socket to read from
+ * @param tc scheduler context (must be shutdown or read ready)
+ */
+static void
+read_response (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
+ struct GNUNET_NETWORK_FDSet *rset;
+
+ rs->read_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
+ {
+ /* timeout or shutdown */
+ cleanup_rs (rs);
+ return;
+ }
+ /* read and process ready sockets */
+ if ((NULL != rs->dnsout4) &&
+ (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
+ (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout4)))
+ rs->dnsout4 = NULL;
+ if ((NULL != rs->dnsout6) &&
+ (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
+ (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout6)))
+ rs->dnsout6 = NULL;
+
+ /* re-schedule read task */
+ rset = GNUNET_NETWORK_fdset_create ();
+ if (NULL != rs->dnsout4)
+ GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
+ if (NULL != rs->dnsout6)
+ GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
+ rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_TIME_absolute_get_remaining (rs->timeout),
+ rset,
+ NULL,
+ &read_response, rs);
+ GNUNET_NETWORK_fdset_destroy (rset);
+}
+
+
+
+/**
+ * Start a DNS stub resolver.
+ *
+ * @param dns_ip target IP address to use
+ * @return NULL on error
+ */
+struct GNUNET_DNSSTUB_Context *
+GNUNET_DNSSTUB_start (const char *dns_ip)
+{
+ struct GNUNET_DNSSTUB_Context *ctx;
+
+ ctx = GNUNET_malloc (sizeof (struct GNUNET_DNSSTUB_Context));
+ if (NULL != dns_ip)
+ ctx->dns_exit = GNUNET_strdup (dns_ip);
+ return ctx;
+}
+
+
+/**
+ * Cleanup DNSSTUB resolver.
+ *
+ * @param ctx stub resolver to clean up
+ */
+void
+GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
+{
+ unsigned int i;
+
+ for (i=0;i<=UINT16_MAX;i++)
+ cleanup_rs (&ctx->sockets[i]);
+ if (NULL != ctx->dns_exit)
+ {
+ GNUNET_free (ctx->dns_exit);
+ ctx->dns_exit = NULL;
+ }
+ GNUNET_free (ctx);
+}
+
+
+/* end of dnsstub.c */
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c
index 76ea1390f4..b13f156a9b 100644
--- a/src/dns/gnunet-service-dns.c
+++ b/src/dns/gnunet-service-dns.c
@@ -45,23 +45,13 @@
#include "dns.h"
#include "gnunet_dns_service.h"
#include "gnunet_dnsparser_lib.h"
+#include "gnunet_dnsstub_lib.h"
#include "gnunet_mesh_service.h"
#include "gnunet_statistics_service.h"
#include "gnunet_tun_lib.h"
/**
- * Timeout for an external (Internet-DNS) DNS resolution
- */
-#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
-
-/**
- * How many DNS sockets do we open at most at the same time?
- * (technical socket maximum is this number x2 for IPv4+IPv6)
- */
-#define DNS_SOCKET_MAX 128
-
-/**
* Phases each request goes through.
*/
enum RequestPhase
@@ -137,34 +127,6 @@ struct ClientRecord
/**
- * UDP socket we are using for sending DNS requests to the Internet.
- */
-struct RequestSocket
-{
-
- /**
- * UDP socket we use for this request for IPv4
- */
- struct GNUNET_NETWORK_Handle *dnsout4;
-
- /**
- * UDP socket we use for this request for IPv6
- */
- struct GNUNET_NETWORK_Handle *dnsout6;
-
- /**
- * Task for reading from dnsout4 and dnsout6.
- */
- GNUNET_SCHEDULER_TaskIdentifier read_task;
-
- /**
- * When should this socket be closed?
- */
- struct GNUNET_TIME_Absolute timeout;
-};
-
-
-/**
* Entry we keep for each active request.
*/
struct RequestRecord
@@ -184,10 +146,9 @@ struct RequestRecord
/**
* Socket we are using to transmit this request (must match if we receive
- * a response). Must NOT be freed as part of this request record (as it
- * might be shared with other requests).
+ * a response).
*/
- struct GNUNET_NETWORK_Handle *dnsout;
+ struct GNUNET_DNSSTUB_RequestSocket *rs;
/**
* Source address of the original request (for sending response).
@@ -200,11 +161,6 @@ struct RequestRecord
struct sockaddr_storage dst_addr;
/**
- * When should this request time out?
- */
- struct GNUNET_TIME_Absolute timeout;
-
- /**
* ID of this request, also basis for hashing. Lowest 16 bit will
* be our message ID when doing a global DNS request and our index
* into the 'requests' array.
@@ -252,25 +208,9 @@ struct TunnelState
/**
* Socket we are using to transmit this request (must match if we receive
- * a response). Must NOT be freed as part of this request record (as it
- * might be shared with other requests).
- */
- struct GNUNET_NETWORK_Handle *dnsout;
-
- /**
- * Address we sent the DNS request to.
- */
- struct sockaddr_storage addr;
-
- /**
- * When should this request time out?
+ * a response).
*/
- struct GNUNET_TIME_Absolute timeout;
-
- /**
- * Number of bytes in 'addr'.
- */
- socklen_t addrlen;
+ struct GNUNET_DNSSTUB_RequestSocket *rs;
/**
* Number of bytes in 'reply'.
@@ -330,19 +270,14 @@ static struct ClientRecord *clients_tail;
static struct GNUNET_SERVER_NotificationContext *nc;
/**
- * Array of all open requests.
- */
-static struct RequestRecord requests[UINT16_MAX + 1];
-
-/**
* Array of all open requests from tunnels.
*/
static struct TunnelState *tunnels[UINT16_MAX + 1];
/**
- * Array of all open sockets for DNS requests.
+ * Array of all open requests.
*/
-static struct RequestSocket sockets[DNS_SOCKET_MAX];
+static struct RequestRecord requests[UINT16_MAX + 1];
/**
* Generator for unique request IDs.
@@ -350,42 +285,15 @@ static struct RequestSocket sockets[DNS_SOCKET_MAX];
static uint64_t request_id_gen;
/**
- * IP address to use for the DNS server if we are a DNS exit service
- * (for VPN via mesh); otherwise NULL.
- */
-static char *dns_exit;
-
-/**
* Handle to the MESH service (for receiving DNS queries), or NULL
* if we are not a DNS exit.
*/
static struct GNUNET_MESH_Handle *mesh;
-
/**
- * We're done with a RequestSocket, close it for now.
- *
- * @param rs request socket to clean up
+ * Handle to the DNS Stub resolver.
*/
-static void
-cleanup_rs (struct RequestSocket *rs)
-{
- if (NULL != rs->dnsout4)
- {
- GNUNET_NETWORK_socket_close (rs->dnsout4);
- rs->dnsout4 = NULL;
- }
- if (NULL != rs->dnsout6)
- {
- GNUNET_NETWORK_socket_close (rs->dnsout6);
- rs->dnsout6 = NULL;
- }
- if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
- {
- GNUNET_SCHEDULER_cancel (rs->read_task);
- rs->read_task = GNUNET_SCHEDULER_NO_TASK;
- }
-}
+static struct GNUNET_DNSSTUB_Context *dnsstub;
/**
@@ -430,10 +338,10 @@ cleanup_task (void *cls GNUNET_UNUSED,
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
stats = NULL;
}
- if (NULL != dns_exit)
+ if (NULL != dnsstub)
{
- GNUNET_free (dns_exit);
- dns_exit = NULL;
+ GNUNET_DNSSTUB_stop (dnsstub);
+ dnsstub = NULL;
}
if (NULL != mesh)
{
@@ -444,54 +352,6 @@ cleanup_task (void *cls GNUNET_UNUSED,
/**
- * Open source port for sending DNS requests
- *
- * @param af AF_INET or AF_INET6
- * @return GNUNET_OK on success
- */
-static struct GNUNET_NETWORK_Handle *
-open_socket (int af)
-{
- struct sockaddr_in a4;
- struct sockaddr_in6 a6;
- struct sockaddr *sa;
- socklen_t alen;
- struct GNUNET_NETWORK_Handle *ret;
-
- ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
- if (NULL == ret)
- return NULL;
- switch (af)
- {
- case AF_INET:
- memset (&a4, 0, alen = sizeof (struct sockaddr_in));
- sa = (struct sockaddr *) &a4;
- break;
- case AF_INET6:
- memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
- sa = (struct sockaddr *) &a6;
- break;
- default:
- GNUNET_break (0);
- GNUNET_NETWORK_socket_close (ret);
- return NULL;
- }
- sa->sa_family = af;
- if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
- sa,
- alen))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not bind to any port: %s\n"),
- STRERROR (errno));
- GNUNET_NETWORK_socket_close (ret);
- return NULL;
- }
- return ret;
-}
-
-
-/**
* We're done with some request, finish processing.
*
* @param rr request send to the network or just clean up.
@@ -677,70 +537,21 @@ send_request_to_client (struct RequestRecord *rr,
}
-/**
- * Read a DNS response from the (unhindered) UDP-Socket
- *
- * @param cls socket to read from
- * @param tc scheduler context (must be shutdown or read ready)
- */
-static void
-read_response (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
-
/**
- * Get a socket of the specified address family to send out a
- * UDP DNS request to the Internet.
+ * Callback called from DNSSTUB resolver when a resolution
+ * succeeded.
*
- * @param af desired address family
- * @return NULL on error (given AF not "supported")
+ * @param cls NULL
+ * @param rs the socket that received the response
+ * @param dns the response itself
+ * @param r number of bytes in dns
*/
-static struct GNUNET_NETWORK_Handle *
-get_request_socket (int af)
-{
- struct RequestSocket *rs;
- struct GNUNET_NETWORK_FDSet *rset;
- static struct GNUNET_NETWORK_Handle *ret;
-
- rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
- DNS_SOCKET_MAX)];
- rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
- switch (af)
- {
- case AF_INET:
- if (NULL == rs->dnsout4)
- rs->dnsout4 = open_socket (AF_INET);
- ret = rs->dnsout4;
- break;
- case AF_INET6:
- if (NULL == rs->dnsout6)
- rs->dnsout6 = open_socket (AF_INET6);
- ret = rs->dnsout6;
- break;
- default:
- return NULL;
- }
- if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
- {
- GNUNET_SCHEDULER_cancel (rs->read_task);
- rs->read_task = GNUNET_SCHEDULER_NO_TASK;
- }
- if ( (NULL == rs->dnsout4) &&
- (NULL == rs->dnsout6) )
- return NULL;
- rset = GNUNET_NETWORK_fdset_create ();
- if (NULL != rs->dnsout4)
- GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
- if (NULL != rs->dnsout6)
- GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
- rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- REQUEST_TIMEOUT,
- rset,
- NULL,
- &read_response, rs);
- GNUNET_NETWORK_fdset_destroy (rset);
- return ret;
-}
+static void
+process_dns_result (void *cls,
+ struct GNUNET_DNSSTUB_RequestSocket *rs,
+ const struct GNUNET_TUN_DnsHeader *dns,
+ size_t r);
/**
@@ -815,8 +626,14 @@ next_phase (struct RequestRecord *rr)
}
rr->phase = RP_INTERNET_DNS;
- rr->dnsout = get_request_socket (rr->dst_addr.ss_family);
- if (NULL == rr->dnsout)
+ rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
+ (struct sockaddr*) &rr->dst_addr,
+ salen,
+ rr->payload,
+ rr->payload_length,
+ &process_dns_result,
+ NULL);
+ if (NULL == rr->rs)
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# DNS exit failed (failed to open socket)"),
@@ -824,12 +641,6 @@ next_phase (struct RequestRecord *rr)
cleanup_rr (rr);
return;
}
- GNUNET_NETWORK_socket_sendto (rr->dnsout,
- rr->payload,
- rr->payload_length,
- (struct sockaddr*) &rr->dst_addr,
- salen);
- rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
return;
case RP_INTERNET_DNS:
rr->phase = RP_MODIFY;
@@ -956,68 +767,32 @@ transmit_reply_to_mesh (void *cls,
}
+
/**
- * Actually do the reading of a DNS packet from our UDP socket and see
- * if we have a valid, matching, pending request.
+ * Callback called from DNSSTUB resolver when a resolution
+ * succeeded.
*
- * @param dnsout socket to read from
- * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
+ * @param cls NULL
+ * @param rs the socket that received the response
+ * @param dns the response itself
+ * @param r number of bytes in dns
*/
-static int
-do_dns_read (struct GNUNET_NETWORK_Handle *dnsout)
+static void
+process_dns_result (void *cls,
+ struct GNUNET_DNSSTUB_RequestSocket *rs,
+ const struct GNUNET_TUN_DnsHeader *dns,
+ size_t r)
{
- struct sockaddr_storage addr;
- socklen_t addrlen;
- struct GNUNET_TUN_DnsHeader *dns;
struct RequestRecord *rr;
struct TunnelState *ts;
- ssize_t r;
- int len;
-
-#ifndef MINGW
- if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
- {
- /* conservative choice: */
- len = UINT16_MAX;
- }
-#else
- /* port the code above? */
- len = UINT16_MAX;
-#endif
-
- {
- unsigned char buf[len] GNUNET_ALIGN;
-
- addrlen = sizeof (addr);
- memset (&addr, 0, sizeof (addr));
- r = GNUNET_NETWORK_socket_recvfrom (dnsout,
- buf, sizeof (buf),
- (struct sockaddr*) &addr, &addrlen);
- if (-1 == r)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
- GNUNET_NETWORK_socket_close (dnsout);
- return GNUNET_SYSERR;
- }
- if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Received DNS response that is too small (%u bytes)"),
- r);
- return GNUNET_NO;
- }
- dns = (struct GNUNET_TUN_DnsHeader *) buf;
- /* Handle case that this is a reply to a request from a MESH DNS tunnel */
- ts = tunnels[dns->id];
- if ( (NULL == ts) ||
- (ts->dnsout != dnsout) ||
- (addrlen != ts->addrlen) ||
- (0 != memcmp (&ts->addr,
- &addr,
- addrlen)) ||
- (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) )
- ts = NULL; /* DNS responder address missmatch */
- if (NULL != ts)
+
+ GNUNET_assert (NULL == cls);
+ /* Handle case that this is a reply to a request from a MESH DNS tunnel */
+ ts = tunnels[dns->id];
+ if ( (NULL == ts) ||
+ (ts->rs != rs) )
+ ts = NULL; /* DNS responder address missmatch */
+ if (NULL != ts)
{
tunnels[dns->id] = NULL;
GNUNET_free_non_null (ts->reply);
@@ -1034,76 +809,25 @@ do_dns_read (struct GNUNET_NETWORK_Handle *dnsout)
&transmit_reply_to_mesh,
ts);
}
- /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
- rr = &requests[dns->id];
- if ( (rr->phase != RP_INTERNET_DNS) ||
- (rr->dnsout != dnsout) ||
- (0 != memcmp (&rr->dst_addr,
- &addr,
- addrlen)) ||
- (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) )
+ /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
+ rr = &requests[dns->id];
+ if ( (rr->phase != RP_INTERNET_DNS) ||
+ (rr->rs != rs) )
{
if (NULL == ts)
- {
- /* unexpected / bogus reply */
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# External DNS response discarded (no matching request)"),
- 1, GNUNET_NO);
- }
- return GNUNET_NO;
+ {
+ /* unexpected / bogus reply */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# External DNS response discarded (no matching request)"),
+ 1, GNUNET_NO);
+ }
+ return;
}
- GNUNET_free_non_null (rr->payload);
- rr->payload = GNUNET_malloc (r);
- memcpy (rr->payload, buf, r);
- rr->payload_length = r;
- next_phase (rr);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Read a DNS response from the (unhindered) UDP-Socket
- *
- * @param cls socket to read from
- * @param tc scheduler context (must be shutdown or read ready)
- */
-static void
-read_response (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct RequestSocket *rs = cls;
- struct GNUNET_NETWORK_FDSet *rset;
-
- rs->read_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
- {
- /* timeout or shutdown */
- cleanup_rs (rs);
- return;
- }
- /* read and process ready sockets */
- if ((NULL != rs->dnsout4) &&
- (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
- (GNUNET_SYSERR == do_dns_read (rs->dnsout4)))
- rs->dnsout4 = NULL;
- if ((NULL != rs->dnsout6) &&
- (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
- (GNUNET_SYSERR == do_dns_read (rs->dnsout6)))
- rs->dnsout6 = NULL;
-
- /* re-schedule read task */
- rset = GNUNET_NETWORK_fdset_create ();
- if (NULL != rs->dnsout4)
- GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
- if (NULL != rs->dnsout6)
- GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
- rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- GNUNET_TIME_absolute_get_remaining (rs->timeout),
- rset,
- NULL,
- &read_response, rs);
- GNUNET_NETWORK_fdset_destroy (rset);
+ GNUNET_free_non_null (rr->payload);
+ rr->payload = GNUNET_malloc (r);
+ memcpy (rr->payload, dns, r);
+ rr->payload_length = r;
+ next_phase (rr);
}
@@ -1410,11 +1134,7 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
char buf[dlen] GNUNET_ALIGN;
struct GNUNET_TUN_DnsHeader *dout;
- struct sockaddr_in v4;
- struct sockaddr_in6 v6;
- struct sockaddr *so;
- socklen_t salen;
-
+
if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
{
GNUNET_break_op (0);
@@ -1428,51 +1148,14 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
UINT16_MAX + 1);
tunnels[ts->my_id] = ts;
memcpy (buf, dns, dlen);
- dout = (struct GNUNET_TUN_DnsHeader*) buf;
+ dout = (struct GNUNET_TUN_DnsHeader *) buf;
dout->id = ts->my_id;
- memset (&v4, 0, sizeof (v4));
- memset (&v6, 0, sizeof (v6));
- if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr))
- {
- salen = sizeof (v4);
- v4.sin_family = AF_INET;
- v4.sin_port = htons (53);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- v4.sin_len = (u_char) salen;
-#endif
- so = (struct sockaddr *) &v4;
- ts->dnsout = get_request_socket (AF_INET);
- }
- else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
- {
- salen = sizeof (v6);
- v6.sin6_family = AF_INET6;
- v6.sin6_port = htons (53);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- v6.sin6_len = (u_char) salen;
-#endif
- so = (struct sockaddr *) &v6;
- ts->dnsout = get_request_socket (AF_INET6);
- }
- else
- {
- GNUNET_break (0);
+ ts->rs = GNUNET_DNSSTUB_resolve2 (dnsstub,
+ buf, dlen,
+ &process_dns_result,
+ NULL);
+ if (NULL == ts->rs)
return GNUNET_SYSERR;
- }
- if (NULL == ts->dnsout)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Configured DNS exit `%s' is not working / valid.\n"),
- dns_exit);
- return GNUNET_SYSERR;
- }
- memcpy (&ts->addr,
- so,
- salen);
- ts->addrlen = salen;
- GNUNET_NETWORK_socket_sendto (ts->dnsout,
- buf, dlen, so, salen);
- ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
return GNUNET_OK;
}
@@ -1552,6 +1235,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
char *ipv6prefix;
struct in_addr dns_exit4;
struct in6_addr dns_exit6;
+ char *dns_exit;
cfg = cfg_;
if (GNUNET_YES !=
@@ -1582,7 +1266,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
GNUNET_free_non_null (dns_exit);
dns_exit = NULL;
}
-
+ dnsstub = GNUNET_DNSSTUB_start (dns_exit);
helper_argv[0] = GNUNET_strdup ("gnunet-dns");
if (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))