From 0ccdd3775b7d005251dc40610d5f92f37f016b4b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 16 Jan 2012 20:00:28 +0000 Subject: [PATCH] -finishing first implementation of protocol translation daemon --- src/pt/gnunet-daemon-pt.c | 278 +++++++++++++++++++++++++++++++++++++- 1 file changed, 277 insertions(+), 1 deletion(-) diff --git a/src/pt/gnunet-daemon-pt.c b/src/pt/gnunet-daemon-pt.c index 762df276e..bbe9477a8 100644 --- a/src/pt/gnunet-daemon-pt.c +++ b/src/pt/gnunet-daemon-pt.c @@ -23,6 +23,10 @@ * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet) * @author Christian Grothoff * + * TODO: + * - add statistics + * - add logging? + * - figure out how/where/when/who tunnels DNS over mesh when necessary! */ #include "platform.h" #include "gnunet_util_lib.h" @@ -32,6 +36,76 @@ #include "gnunet_statistics_service.h" +/** + * After how long do we time out if we could not get an IP from VPN? + */ +#define TIMEOUT GNUNET_TIME_UNIT_MINUTES + + +/** + * Which group of DNS records are we currently processing? + */ +enum RequestGroup + { + /** + * DNS answers + */ + ANSWERS = 0, + + /** + * DNS authority records + */ + AUTHORITY_RECORDS = 1, + + /** + * DNS additional records + */ + ADDITIONAL_RECORDS = 2, + /** + * We're done processing. + */ + END = 3 + }; + + +/** + * Information tracked per DNS request that we are processing. + */ +struct RequestContext +{ + /** + * Handle to submit the final result. + */ + struct GNUNET_DNS_RequestHandle *rh; + + /** + * DNS packet that is being modified. + */ + struct GNUNET_DNSPARSER_Packet *dns; + + /** + * Active redirection request with the VPN. + */ + struct GNUNET_VPN_RedirectionRequest *rr; + + /** + * Record for which we have an active redirection request. + */ + struct GNUNET_DNSPARSER_Record *rec; + + /** + * Offset in the current record group that is being modified. + */ + unsigned int offset; + + /** + * Group that is being modified + */ + enum RequestGroup group; + +}; + + /** * The handle to the configuration used throughout the process */ @@ -63,6 +137,202 @@ static int ipv4_pt; static int ipv6_pt; +/** + * We're done modifying all records in the response. Submit the reply + * and free the resources of the rc. + * + * @param rc context to process + */ +static void +finish_request (struct RequestContext *rc) +{ + char *buf; + size_t buf_len; + + if (GNUNET_SYSERR == + GNUNET_DNSPARSER_pack (rc->dns, + 16 * 1024, + &buf, + &buf_len)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to pack DNS request. Dropping.\n")); + GNUNET_DNS_request_drop (rc->rh); + } + else + { + GNUNET_DNS_request_answer (rc->rh, + buf_len, buf); + GNUNET_free (buf); + } + GNUNET_DNSPARSER_free_packet (rc->dns); + GNUNET_free (rc); +} + + +/** + * Process the next record of the given request context. + * When done, submit the reply and free the resources of + * the rc. + * + * @param rc context to process + */ +static void +submit_request (struct RequestContext *rc); + + +/** + * 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. We substitute the active + * record and then continue with 'submit_request' to look at + * the other records. + * + * @param cls our 'struct RequestContext' + * @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_callback (void *cls, + int af, + const void *address) +{ + struct RequestContext *rc = cls; + + rc->rr = NULL; + if (af == AF_UNSPEC) + { + GNUNET_DNS_request_drop (rc->rh); + GNUNET_DNSPARSER_free_packet (rc->dns); + GNUNET_free (rc); + return; + } + switch (rc->rec->type) + { + case GNUNET_DNSPARSER_TYPE_A: + GNUNET_assert (AF_INET == af); + memcpy (rc->rec->data.raw.data, address, sizeof (struct in_addr)); + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + GNUNET_assert (AF_INET6 == af); + memcpy (rc->rec->data.raw.data, address, sizeof (struct in6_addr)); + break; + default: + GNUNET_assert (0); + return; + } + rc->rec = NULL; + submit_request (rc); +} + + +/** + * Modify the given DNS record by asking VPN to create a tunnel + * to the given address. When done, continue with submitting + * other records from the request context ('submit_request' is + * our continuation). + * + * @param rc context to process + * @param rec record to modify + */ +static void +modify_address (struct RequestContext *rc, + struct GNUNET_DNSPARSER_Record *rec) +{ + int af; + + switch (rec->type) + { + case GNUNET_DNSPARSER_TYPE_A: + af = AF_INET; + GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr)); + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + af = AF_INET6; + GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr)); + break; + default: + GNUNET_assert (0); + return; + } + rc->rec = rec; + rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle, + af, af, + rec->data.raw.data, + GNUNET_NO /* nac */, + GNUNET_TIME_relative_to_absolute (TIMEOUT), + &vpn_allocation_callback, + rc); +} + + +/** + * Process the next record of the given request context. + * When done, submit the reply and free the resources of + * the rc. + * + * @param rc context to process + */ +static void +submit_request (struct RequestContext *rc) +{ + struct GNUNET_DNSPARSER_Record *ra; + unsigned int ra_len; + unsigned int i; + + while (1) + { + switch (rc->group) + { + case ANSWERS: + ra = rc->dns->answers; + ra_len = rc->dns->num_answers; + break; + case AUTHORITY_RECORDS: + ra = rc->dns->authority_records; + ra_len = rc->dns->num_authority_records; + break; + case ADDITIONAL_RECORDS: + ra = rc->dns->additional_records; + ra_len = rc->dns->num_additional_records; + break; + case END: + finish_request (rc); + return; + default: + GNUNET_assert (0); + } + for (i=rc->offset;ioffset = i + 1; + modify_address (rc, &ra[i]); + return; + } + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + if (ipv6_pt) + { + rc->offset = i + 1; + modify_address (rc, &ra[i]); + return; + } + break; + } + } + rc->group++; + } +} + + /** * Test if any of the given records need protocol-translation work. * @@ -124,6 +394,7 @@ dns_request_handler (void *cls, const char *request) { struct GNUNET_DNSPARSER_Packet *dns; + struct RequestContext *rc; int work; dns = GNUNET_DNSPARSER_parse (request, request_length); @@ -143,7 +414,12 @@ dns_request_handler (void *cls, GNUNET_DNS_request_forward (rh); return; } - /* FIXME: translate A/AAAA records using VPN! */ + rc = GNUNET_malloc (sizeof (struct RequestContext)); + rc->rh = rh; + rc->dns = dns; + rc->offset = 0; + rc->group = ANSWERS; + submit_request (rc); } -- 2.25.1