summaryrefslogtreecommitdiff
path: root/src/gns/gnunet-dns2gns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gns/gnunet-dns2gns.c')
-rw-r--r--src/gns/gnunet-dns2gns.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/gns/gnunet-dns2gns.c b/src/gns/gnunet-dns2gns.c
index 06f4c9841..46659cdda 100644
--- a/src/gns/gnunet-dns2gns.c
+++ b/src/gns/gnunet-dns2gns.c
@@ -27,6 +27,7 @@
#include <gnunet_dnsparser_lib.h>
#include <gnunet_gns_service.h>
#include <gnunet_dnsstub_lib.h>
+#include "gnunet_vpn_service.h"
#include "gns.h"
/**
@@ -35,6 +36,46 @@
#define TIMEOUT GNUNET_TIME_UNIT_MINUTES
/**
+ * Default timeout for VPN redirections.
+ */
+#define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
+
+
+struct Request;
+
+/**
+ * Closure for #vpn_allocation_cb.
+ */
+struct VpnContext
+{
+ /**
+ * Which resolution process are we processing.
+ */
+ struct Request *request;
+
+ /**
+ * Handle to the VPN request that we were performing.
+ */
+ struct GNUNET_VPN_RedirectionRequest *vpn_request;
+
+ /**
+ * Number of records serialized in @e rd_data.
+ */
+ unsigned int rd_count;
+
+ /**
+ * Serialized records.
+ */
+ char *rd_data;
+
+ /**
+ * Number of bytes in @e rd_data.
+ */
+ ssize_t rd_data_size;
+};
+
+
+/**
* Data kept per request.
*/
struct Request
@@ -72,6 +113,11 @@ struct Request
struct GNUNET_SCHEDULER_Task *timeout_task;
/**
+ * Vpn resulution context
+ */
+ struct VpnContext *vpn_ctx;
+
+ /**
* Original UDP request message.
*/
char *udp_msg;
@@ -90,6 +136,7 @@ struct Request
* ID of the original request.
*/
uint16_t original_request_id;
+
};
/**
@@ -109,6 +156,11 @@ static struct in6_addr address6;
struct GNUNET_GNS_Handle *gns;
/**
+ * Our handle to the vpn service
+ */
+static struct GNUNET_VPN_Handle *vpn_handle;
+
+/**
* Stub resolver
*/
struct GNUNET_DNSSTUB_Context *dns_stub;
@@ -183,6 +235,11 @@ do_shutdown (void *cls)
GNUNET_GNS_disconnect (gns);
gns = NULL;
}
+ if (NULL != vpn_handle)
+ {
+ GNUNET_VPN_disconnect (vpn_handle);
+ vpn_handle = NULL;
+ }
if (NULL != dns_stub)
{
GNUNET_DNSSTUB_stop (dns_stub);
@@ -269,6 +326,7 @@ static void
do_timeout (void *cls)
{
struct Request *request = cls;
+ struct VpnContext *vpn_ctx;
if (NULL != request->packet)
GNUNET_DNSPARSER_free_packet (request->packet);
@@ -277,6 +335,12 @@ do_timeout (void *cls)
if (NULL != request->dns_lookup)
GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
GNUNET_free (request->udp_msg);
+ if (NULL != (vpn_ctx = request->vpn_ctx))
+ {
+ GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
+ GNUNET_free (vpn_ctx->rd_data);
+ GNUNET_free (vpn_ctx);
+ }
GNUNET_free (request);
}
@@ -321,6 +385,79 @@ dns_result_processor (void *cls,
send_response (request);
}
+/**
+ * Callback invoked from the VPN service once a redirection is
+ * available. Provides the IP address that can now be used to
+ * reach the requested destination. Replaces the "VPN" record
+ * with the respective A/AAAA record and continues processing.
+ *
+ * @param cls closure
+ * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
+ * will match 'result_af' from the request
+ * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
+ * that the VPN allocated for the redirection;
+ * traffic to this IP will now be redirected to the
+ * specified target peer; NULL on error
+ */
+static void
+vpn_allocation_cb (void *cls,
+ int af,
+ const void *address)
+{
+ struct VpnContext *vpn_ctx = cls;
+ struct Request *request = vpn_ctx->request;
+ struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
+ unsigned int i;
+
+ vpn_ctx->vpn_request = NULL;
+ request->vpn_ctx = NULL;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_GNSRECORD_records_deserialize (
+ (size_t) vpn_ctx->rd_data_size,
+ vpn_ctx->rd_data,
+ vpn_ctx->rd_count,
+ rd));
+ for (i = 0; i < vpn_ctx->rd_count; i++)
+ {
+ if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
+ {
+ switch (af)
+ {
+ case AF_INET:
+ rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
+ rd[i].data_size = sizeof(struct in_addr);
+ rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
+ VPN_TIMEOUT).abs_value_us;
+ rd[i].flags = 0;
+ rd[i].data = address;
+ break;
+
+ case AF_INET6:
+ rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
+ rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
+ VPN_TIMEOUT).abs_value_us;
+ rd[i].flags = 0;
+ rd[i].data = address;
+ rd[i].data_size = sizeof(struct in6_addr);
+ break;
+
+ default:
+ GNUNET_assert (0);
+ }
+ break;
+ }
+ }
+ GNUNET_assert (i < vpn_ctx->rd_count);
+ if (0 == vpn_ctx->rd_count)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _ ("VPN returned empty result for `%s'\n"),
+ request->packet->queries[0].name);
+ send_response (request);
+ GNUNET_free (vpn_ctx->rd_data);
+ GNUNET_free (vpn_ctx);
+}
+
+
/**
* Iterator called on obtained result for a GNS lookup.
@@ -339,6 +476,11 @@ result_processor (void *cls,
struct Request *request = cls;
struct GNUNET_DNSPARSER_Packet *packet;
struct GNUNET_DNSPARSER_Record rec;
+ struct VpnContext *vpn_ctx;
+ const struct GNUNET_TUN_GnsVpnRecord *vpn;
+ const char *vname;
+ struct GNUNET_HashCode vhash;
+ int af;
request->lookup = NULL;
if (GNUNET_NO == was_gns)
@@ -415,6 +557,67 @@ result_processor (void *cls,
packet->num_answers,
rec);
break;
+ case GNUNET_GNSRECORD_TYPE_VPN:
+ if ((GNUNET_DNSPARSER_TYPE_A != request->packet->queries[0].type) &&
+ (GNUNET_DNSPARSER_TYPE_AAAA != request->packet->queries[0].type))
+ break;
+ af = (GNUNET_DNSPARSER_TYPE_A == request->packet->queries[0].type) ? AF_INET :
+ AF_INET6;
+ if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
+ rd[i].data_size)
+ {
+ GNUNET_break_op (0);
+ break;
+ }
+ vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
+ vname = (const char *) &vpn[1];
+ if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
+ GNUNET_TUN_GnsVpnRecord)
+ ])
+ {
+ GNUNET_break_op (0);
+ break;
+ }
+ GNUNET_TUN_service_name_to_hash (vname,
+ &vhash);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
+ GNUNET_i2s (&vpn->peer),
+ vname,
+ (int) af,
+ (int) ntohs (vpn->proto));
+ vpn_ctx = GNUNET_new (struct VpnContext);
+ request->vpn_ctx = vpn_ctx;
+ vpn_ctx->request = request;
+ vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
+ rd);
+ if (vpn_ctx->rd_data_size < 0)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (vpn_ctx);
+ break;
+ }
+ vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
+ vpn_ctx->rd_count = rd_count;
+ GNUNET_assert (vpn_ctx->rd_data_size ==
+ GNUNET_GNSRECORD_records_serialize (rd_count,
+ rd,
+ (size_t) vpn_ctx
+ ->rd_data_size,
+ vpn_ctx->rd_data));
+ vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
+ af,
+ ntohs (
+ vpn->proto),
+ &vpn->peer,
+ &vhash,
+ GNUNET_TIME_relative_to_absolute (
+ VPN_TIMEOUT),
+ &
+ vpn_allocation_cb,
+ vpn_ctx);
+ return;
+
default:
/* skip */
@@ -641,6 +844,8 @@ run (void *cls,
NULL);
if (NULL == (gns = GNUNET_GNS_connect (cfg)))
return;
+ if (NULL == (vpn_handle = GNUNET_VPN_connect (cfg)))
+ return;
GNUNET_assert (NULL != (dns_stub = GNUNET_DNSSTUB_start (128)));
if (GNUNET_OK !=
GNUNET_DNSSTUB_add_dns_ip (dns_stub,
@@ -649,6 +854,8 @@ run (void *cls,
GNUNET_DNSSTUB_stop (dns_stub);
GNUNET_GNS_disconnect (gns);
gns = NULL;
+ GNUNET_VPN_disconnect (vpn_handle);
+ vpn_handle = NULL;
return;
}
@@ -750,6 +957,8 @@ run (void *cls,
{
GNUNET_GNS_disconnect (gns);
gns = NULL;
+ GNUNET_VPN_disconnect (vpn_handle);
+ vpn_handle = NULL;
GNUNET_DNSSTUB_stop (dns_stub);
dns_stub = NULL;
return;