/** * The DNS request handler. Called for every incoming DNS request. * * @param cls closure, unused * @param rh request handle to user for reply * @param request_length number of bytes in @a request * @param request UDP payload of the DNS request */ static void handle_dns_request (void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { struct GNUNET_DNSPARSER_Packet *p; struct InterceptLookupHandle *ilh; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request. Processing.\n"); if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received malformed DNS packet, leaving it untouched.\n"); GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet (p); return; } /* Check TLD and decide if we or legacy dns is responsible */ if (1 != p->num_queries) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not exactly one query in DNS packet. Forwarding untouched.\n"); GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet(p); return; } /* Check for GNS TLDs. */ if ( (GNUNET_YES == is_gnu_tld (p->queries[0].name)) || (GNUNET_YES == is_zkey_tld (p->queries[0].name)) || (0 == strcmp (p->queries[0].name, GNUNET_GNS_TLD)) ) { /* Start resolution in GNS */ ilh = GNUNET_new (struct InterceptLookupHandle); GNUNET_CONTAINER_DLL_insert (ilh_head, ilh_tail, ilh); ilh->packet = p; ilh->request_handle = rh; ilh->lookup = GNS_resolver_lookup (&zone, p->queries[0].type, p->queries[0].name, NULL /* FIXME: enable shorten for DNS intercepts? */, GNUNET_NO, &reply_to_dns, ilh); return; }
/** * Signature of a function that is called whenever the DNS service * encounters a DNS request and needs to do something with it. The * function has then the chance to generate or modify the response by * calling one of the three "GNUNET_DNS_request_*" continuations. * * When a request is intercepted, this function is called first to * give the client a chance to do the complete address resolution; * "rdata" will be NULL for this first call for a DNS request, unless * some other client has already filled in a response. * * If multiple clients exist, all of them are called before the global * DNS. The global DNS is only called if all of the clients' * functions call GNUNET_DNS_request_forward. Functions that call * GNUNET_DNS_request_forward will be called again before a final * response is returned to the application. If any of the clients' * functions call GNUNET_DNS_request_drop, the response is dropped. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ static void modify_request (void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { struct GNUNET_DNSPARSER_Packet *p; unsigned int i; char *buf; size_t len; int ret; p = GNUNET_DNSPARSER_parse (request, request_length); if (NULL == p) { fprintf (stderr, "Received malformed DNS packet, leaving it untouched\n"); GNUNET_DNS_request_forward (rh); return; } for (i=0;i<p->num_answers;i++) modify_record (&p->answers[i]); buf = NULL; ret = GNUNET_DNSPARSER_pack (p, 1024, &buf, &len); GNUNET_DNSPARSER_free_packet (p); if (GNUNET_OK != ret) { if (GNUNET_NO == ret) fprintf (stderr, "Modified DNS response did not fit, keeping old response\n"); else GNUNET_break (0); /* our modifications should have been sane! */ GNUNET_DNS_request_forward (rh); } else { if (verbosity > 0) fprintf (stdout, "Injecting modified DNS response\n"); GNUNET_DNS_request_answer (rh, len, buf); } GNUNET_free_non_null (buf); }
/** * This function is called AFTER we got an IP address for a * DNS request. Now, the PT daemon has the chance to substitute * the IP address with one from the VPN range to tunnel requests * destined for this IP address via VPN and MESH. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ static void dns_post_request_handler (void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { struct GNUNET_DNSPARSER_Packet *dns; struct ReplyContext *rc; int work; GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS replies intercepted"), 1, GNUNET_NO); dns = GNUNET_DNSPARSER_parse (request, request_length); if (NULL == dns) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse DNS request. Dropping.\n")); GNUNET_DNS_request_drop (rh); return; } work = GNUNET_NO; work |= work_test (dns->answers, dns->num_answers); work |= work_test (dns->authority_records, dns->num_authority_records); work |= work_test (dns->additional_records, dns->num_additional_records); if (! work) { GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet (dns); return; } rc = GNUNET_malloc (sizeof (struct ReplyContext)); rc->rh = rh; rc->dns = dns; rc->offset = 0; rc->group = ANSWERS; submit_request (rc); }