From f3eaf5dae9a14fc62109b6e7c69571a068301fed Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Thu, 3 Feb 2022 22:47:03 +0100 Subject: GNS: Move VPN to DNS2GNS. Fixes #7171 --- src/gns/gnunet-dns2gns.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) (limited to 'src/gns/gnunet-dns2gns.c') 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 #include #include +#include "gnunet_vpn_service.h" #include "gns.h" /** @@ -34,6 +35,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. */ @@ -71,6 +112,11 @@ struct Request */ struct GNUNET_SCHEDULER_Task *timeout_task; + /** + * Vpn resulution context + */ + struct VpnContext *vpn_ctx; + /** * Original UDP request message. */ @@ -90,6 +136,7 @@ struct Request * ID of the original request. */ uint16_t original_request_id; + }; /** @@ -108,6 +155,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 */ @@ -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; -- cgit v1.2.3