2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
17 * @file dns/gnunet-service-dns.c
18 * @brief service to intercept and modify DNS queries (and replies) of this system
19 * @author Christian Grothoff
21 * For "secure" interaction with the legacy DNS system, we permit
22 * replies only to arrive within a 5s window (and they must match
23 * ports, IPs and request IDs). Furthermore, we let the OS pick a
24 * source port, opening up to 128 sockets per address family (IPv4 or
25 * IPv6). Those sockets are closed if they are not in use for 5s
26 * (which means they will be freshly randomized afterwards). For new
27 * requests, we pick a random slot in the array with 128 socket slots
28 * (and re-use an existing socket if the slot is still in use). Thus
29 * each request will be given one of 128 random source ports, and the
30 * 128 random source ports will also change "often" (less often if the
31 * system is very busy, each time if we are mostly idle). At the same
32 * time, the system will never use more than 256 UDP sockets.
35 #include "gnunet_util_lib.h"
36 #include "gnunet_applications.h"
37 #include "gnunet_constants.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_signatures.h"
41 #include "gnunet_dns_service.h"
42 #include "gnunet_dnsparser_lib.h"
43 #include "gnunet_dnsstub_lib.h"
44 #include "gnunet_statistics_service.h"
45 #include "gnunet_tun_lib.h"
54 * Generic logging shorthand
56 #define LOG(kind, ...) \
57 GNUNET_log_from (kind, "dns", __VA_ARGS__);
61 * Phases each request goes through.
66 * Request has just been received.
71 * Showing the request to all monitor clients. If
72 * client list is empty, will enter QUERY phase.
77 * Showing the request to PRE-RESOLUTION clients to find an answer.
78 * If client list is empty, will trigger global DNS request.
83 * Global Internet query is now pending.
88 * Client (or global DNS request) has resulted in a response.
89 * Forward to all POST-RESOLUTION clients. If client list is empty,
90 * will enter RESPONSE_MONITOR phase.
95 * Showing the request to all monitor clients. If
96 * client list is empty, give the result to the hijacker (and be done).
101 * Some client has told us to drop the request.
108 * Entry we keep for each client.
113 * Kept in doubly-linked list.
115 struct ClientRecord *next;
118 * Kept in doubly-linked list.
120 struct ClientRecord *prev;
123 * Handle to the client.
125 struct GNUNET_SERVICE_Client *client;
128 * Message queue to talk to @a client.
130 struct GNUNET_MQ_Handle *mq;
133 * Flags for the client.
135 enum GNUNET_DNS_Flags flags;
141 * Entry we keep for each active request.
147 * List of clients that still need to see this request (each entry
148 * is set to NULL when the client is done).
150 struct ClientRecord **client_wait_list;
153 * Payload of the UDP packet (the UDP payload), can be either query
154 * or already the response.
159 * Socket we are using to transmit this request (must match if we receive
162 struct GNUNET_DNSSTUB_RequestSocket *rs;
165 * Source address of the original request (for sending response).
167 struct sockaddr_storage src_addr;
170 * Destination address of the original request (for potential use as exit).
172 struct sockaddr_storage dst_addr;
175 * ID of this request, also basis for hashing. Lowest 16 bit will
176 * be our message ID when doing a global DNS request and our index
177 * into the 'requests' array.
182 * Number of bytes in payload.
184 size_t payload_length;
187 * Length of the @e client_wait_list.
189 unsigned int client_wait_list_length;
192 * In which phase this this request?
194 enum RequestPhase phase;
200 * Global return value from 'main'.
202 static int global_ret;
205 * The configuration to use
207 static const struct GNUNET_CONFIGURATION_Handle *cfg;
212 static struct GNUNET_STATISTICS_Handle *stats;
215 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
217 static struct GNUNET_HELPER_Handle *hijacker;
220 * Command-line arguments we are giving to the hijacker process.
222 static char *helper_argv[8];
225 * Head of DLL of clients we consult.
227 static struct ClientRecord *clients_head;
230 * Tail of DLL of clients we consult.
232 static struct ClientRecord *clients_tail;
235 * Array of all open requests.
237 static struct RequestRecord requests[UINT16_MAX + 1];
240 * Generator for unique request IDs.
242 static uint64_t request_id_gen;
245 * Handle to the DNS Stub resolver.
247 static struct GNUNET_DNSSTUB_Context *dnsstub;
251 * We're done processing a DNS request, free associated memory.
253 * @param rr request to clean up
256 cleanup_rr (struct RequestRecord *rr)
258 GNUNET_free_non_null (rr->payload);
260 rr->payload_length = 0;
261 GNUNET_array_grow (rr->client_wait_list,
262 rr->client_wait_list_length,
268 * Task run during shutdown.
273 cleanup_task (void *cls GNUNET_UNUSED)
275 if (NULL != hijacker)
277 GNUNET_HELPER_stop (hijacker, GNUNET_NO);
280 for (unsigned int i=0;i<8;i++)
281 GNUNET_free_non_null (helper_argv[i]);
282 for (unsigned int i=0;i<=UINT16_MAX;i++)
283 cleanup_rr (&requests[i]);
286 GNUNET_STATISTICS_destroy (stats,
292 GNUNET_DNSSTUB_stop (dnsstub);
299 * We're done with some request, finish processing.
301 * @param rr request send to the network or just clean up.
304 request_done (struct RequestRecord *rr)
306 struct GNUNET_MessageHeader *hdr;
308 uint16_t source_port;
309 uint16_t destination_port;
311 GNUNET_array_grow (rr->client_wait_list,
312 rr->client_wait_list_length,
314 if (RP_RESPONSE_MONITOR != rr->phase)
316 /* no response, drop */
317 LOG (GNUNET_ERROR_TYPE_DEBUG,
318 "Got no response for request %llu, dropping\n",
319 (unsigned long long) rr->request_id);
324 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "Transmitting response for request %llu\n",
326 (unsigned long long) rr->request_id);
327 /* send response via hijacker */
328 reply_len = sizeof (struct GNUNET_MessageHeader);
329 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
330 switch (rr->src_addr.ss_family)
333 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
336 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
343 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
344 reply_len += rr->payload_length;
345 if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
347 /* response too big, drop */
348 GNUNET_break (0); /* how can this be? */
353 char buf[reply_len] GNUNET_ALIGN;
355 struct GNUNET_TUN_IPv4Header ip4;
356 struct GNUNET_TUN_IPv6Header ip6;
358 /* first, GNUnet message header */
359 hdr = (struct GNUNET_MessageHeader*) buf;
360 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
361 hdr->size = htons ((uint16_t) reply_len);
362 off = sizeof (struct GNUNET_MessageHeader);
364 /* first, TUN header */
366 struct GNUNET_TUN_Layer2PacketHeader tun;
368 tun.flags = htons (0);
369 if (rr->src_addr.ss_family == AF_INET)
370 tun.proto = htons (ETH_P_IPV4);
372 tun.proto = htons (ETH_P_IPV6);
373 GNUNET_memcpy (&buf[off],
375 sizeof (struct GNUNET_TUN_Layer2PacketHeader));
376 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
380 switch (rr->src_addr.ss_family)
384 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
385 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
387 source_port = dst->sin_port;
388 destination_port = src->sin_port;
389 GNUNET_TUN_initialize_ipv4_header (&ip4,
391 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
394 GNUNET_memcpy (&buf[off],
402 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
403 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
405 source_port = dst->sin6_port;
406 destination_port = src->sin6_port;
407 GNUNET_TUN_initialize_ipv6_header (&ip6,
409 reply_len - off - sizeof (struct GNUNET_TUN_IPv6Header),
412 GNUNET_memcpy (&buf[off],
424 struct GNUNET_TUN_UdpHeader udp;
426 udp.source_port = source_port;
427 udp.destination_port = destination_port;
428 udp.len = htons (reply_len - off);
429 if (AF_INET == rr->src_addr.ss_family)
430 GNUNET_TUN_calculate_udp4_checksum (&ip4,
435 GNUNET_TUN_calculate_udp6_checksum (&ip6,
439 GNUNET_memcpy (&buf[off],
445 /* now DNS payload */
447 GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
448 off += rr->payload_length;
450 /* final checks & sending */
451 GNUNET_assert (off == reply_len);
452 (void) GNUNET_HELPER_send (hijacker,
456 GNUNET_STATISTICS_update (stats,
457 gettext_noop ("# DNS requests answered via TUN interface"),
460 /* clean up, we're done */
466 * Show the payload of the given request record to the client
467 * (and wait for a response).
469 * @param rr request to send to client
470 * @param cr client to send the response to
473 send_request_to_client (struct RequestRecord *rr,
474 struct ClientRecord *cr)
476 struct GNUNET_MQ_Envelope *env;
477 struct GNUNET_DNS_Request *req;
479 if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_MAX_MESSAGE_SIZE)
485 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "Sending information about request %llu to local client\n",
487 (unsigned long long) rr->request_id);
488 env = GNUNET_MQ_msg_extra (req,
490 GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
491 req->reserved = htonl (0);
492 req->request_id = rr->request_id;
493 GNUNET_memcpy (&req[1],
496 GNUNET_MQ_send (cr->mq,
502 * Callback called from DNSSTUB resolver when a resolution
506 * @param dns the response itself
507 * @param r number of bytes in dns
510 process_dns_result (void *cls,
511 const struct GNUNET_TUN_DnsHeader *dns,
516 * A client has completed its processing for this
519 * @param rr request to process further
522 next_phase (struct RequestRecord *rr)
524 struct ClientRecord *cr;
527 if (rr->phase == RP_DROP)
533 for (unsigned int j=0;j<rr->client_wait_list_length;j++)
535 if (NULL != rr->client_wait_list[j])
543 send_request_to_client (rr,
544 rr->client_wait_list[nz]);
547 /* done with current phase, advance! */
548 LOG (GNUNET_ERROR_TYPE_DEBUG,
549 "Request %llu now in phase %d\n",
555 rr->phase = RP_REQUEST_MONITOR;
556 for (cr = clients_head; NULL != cr; cr = cr->next)
558 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
559 GNUNET_array_append (rr->client_wait_list,
560 rr->client_wait_list_length,
565 case RP_REQUEST_MONITOR:
566 rr->phase = RP_QUERY;
567 for (cr = clients_head; NULL != cr; cr = cr->next)
569 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
570 GNUNET_array_append (rr->client_wait_list,
571 rr->client_wait_list_length,
578 /* TODO: optionally, use this to forward DNS requests to the
579 *original* DNS server instead of the one we have configured...
580 (but then we need to create a fresh dnsstub for each request
581 *and* manage the timeout) */
582 switch (rr->dst_addr.ss_family)
585 salen = sizeof (struct sockaddr_in);
586 sa = (const struct sockaddr *) &rr->dst_addr;
589 salen = sizeof (struct sockaddr_in6);
590 sa = (const struct sockaddr *) &rr->dst_addr;
596 rr->phase = RP_INTERNET_DNS;
597 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
604 GNUNET_STATISTICS_update (stats,
605 gettext_noop ("# DNS exit failed (failed to open socket)"),
612 case RP_INTERNET_DNS:
613 rr->phase = RP_MODIFY;
614 for (cr = clients_head; NULL != cr; cr = cr->next)
616 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
617 GNUNET_array_append (rr->client_wait_list,
618 rr->client_wait_list_length,
624 rr->phase = RP_RESPONSE_MONITOR;
625 for (cr = clients_head; NULL != cr; cr = cr->next)
627 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
628 GNUNET_array_append (rr->client_wait_list,
629 rr->client_wait_list_length,
634 case RP_RESPONSE_MONITOR:
649 * A client connected, setup our data structures.
652 * @param client handle of client that connected
653 * @param mq message queue to talk to @a client
654 * @return our `struct ClientRecord`
657 client_connect_cb (void *cls,
658 struct GNUNET_SERVICE_Client *client,
659 struct GNUNET_MQ_Handle *mq)
661 struct ClientRecord *cr = cls;
663 cr = GNUNET_new (struct ClientRecord);
666 GNUNET_CONTAINER_DLL_insert (clients_head,
674 * A client disconnected, clean up after it.
677 * @param client handle of client that disconnected
678 * @param app_ctx our `struct ClientRecord`
681 client_disconnect_cb (void *cls,
682 struct GNUNET_SERVICE_Client *client,
685 struct ClientRecord *cr = app_ctx;
686 struct RequestRecord *rr;
688 GNUNET_CONTAINER_DLL_remove (clients_head,
691 for (unsigned int i=0;i<UINT16_MAX;i++)
694 if (0 == rr->client_wait_list_length)
695 continue; /* not in use */
696 for (unsigned int j=0;j<rr->client_wait_list_length;j++)
698 if (rr->client_wait_list[j] == cr)
700 rr->client_wait_list[j] = NULL;
710 * Callback called from DNSSTUB resolver when a resolution
714 * @param dns the response itself
715 * @param r number of bytes in dns
718 process_dns_result (void *cls,
719 const struct GNUNET_TUN_DnsHeader *dns,
722 struct RequestRecord *rr;
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
725 "Processing DNS result from stub resolver\n");
726 GNUNET_assert (NULL == cls);
730 rr = &requests[dns->id];
731 if (rr->phase != RP_INTERNET_DNS)
733 /* unexpected / bogus reply */
734 GNUNET_STATISTICS_update (stats,
735 gettext_noop ("# External DNS response discarded (no matching request)"),
737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
738 "Received DNS reply that does not match any pending request. Dropping.\n");
741 LOG (GNUNET_ERROR_TYPE_DEBUG,
742 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
743 (unsigned long long) rr->request_id);
744 GNUNET_free_non_null (rr->payload);
745 rr->payload = GNUNET_malloc (r);
746 GNUNET_memcpy (rr->payload,
749 rr->payload_length = r;
755 * We got a new client. Make sure all new DNS requests pass by its desk.
757 * @param cls the client
758 * @param reg the init message
761 handle_client_init (void *cls,
762 const struct GNUNET_DNS_Register *reg)
764 struct ClientRecord *cr = cls;
766 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
767 GNUNET_SERVICE_client_continue (cr->client);
772 * Check a response from a client.
774 * @param cls the client
775 * @param resp the response
776 * @return #GNUNET_OK (always fine)
779 check_client_response (void *cls,
780 const struct GNUNET_DNS_Response *resp)
782 return GNUNET_OK; /* any payload is acceptable */
787 * Handle a response from a client.
789 * @param cls the client
790 * @param resp the response
793 handle_client_response (void *cls,
794 const struct GNUNET_DNS_Response *resp)
796 struct ClientRecord *cr = cls;
797 struct RequestRecord *rr;
801 msize = ntohs (resp->header.size);
802 off = (uint16_t) resp->request_id;
804 LOG (GNUNET_ERROR_TYPE_DEBUG,
805 "Received DNS response with ID %llu from local client!\n",
806 (unsigned long long) resp->request_id);
807 if (rr->request_id != resp->request_id)
809 GNUNET_STATISTICS_update (stats,
810 gettext_noop ("# Client response discarded (no matching request)"),
813 GNUNET_SERVICE_client_continue (cr->client);
816 for (unsigned int i=0;i<rr->client_wait_list_length;i++)
818 if (NULL == rr->client_wait_list[i])
820 if (rr->client_wait_list[i] != cr)
822 rr->client_wait_list[i] = NULL;
823 switch (ntohl (resp->drop_flag))
828 case 1: /* no change */
831 msize -= sizeof (struct GNUNET_DNS_Response);
832 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
833 (RP_REQUEST_MONITOR == rr->phase) ||
834 (RP_RESPONSE_MONITOR == rr->phase) )
837 GNUNET_SERVICE_client_drop (cr->client);
841 GNUNET_free_non_null (rr->payload);
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 "Changing DNS reply according to client specifications\n");
844 rr->payload = GNUNET_malloc (msize);
845 rr->payload_length = msize;
846 GNUNET_memcpy (rr->payload, &resp[1], msize);
847 if (rr->phase == RP_QUERY)
849 /* clear wait list, we're moving to MODIFY phase next */
850 GNUNET_array_grow (rr->client_wait_list,
851 rr->client_wait_list_length,
854 /* if query changed to answer, move past DNS resolution phase... */
855 if ( (RP_QUERY == rr->phase) &&
856 (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
857 ((struct GNUNET_TUN_DnsFlags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
859 rr->phase = RP_INTERNET_DNS;
860 GNUNET_array_grow (rr->client_wait_list,
861 rr->client_wait_list_length,
867 GNUNET_SERVICE_client_continue (cr->client);
870 /* odd, client was not on our list for the request, that ought
873 GNUNET_SERVICE_client_drop (cr->client);
878 * Functions with this signature are called whenever a complete
879 * message is received by the tokenizer from the DNS hijack process.
882 * @param message the actual message, a DNS request we should handle
885 process_helper_messages (void *cls,
886 const struct GNUNET_MessageHeader *message)
889 const struct GNUNET_TUN_Layer2PacketHeader *tun;
890 const struct GNUNET_TUN_IPv4Header *ip4;
891 const struct GNUNET_TUN_IPv6Header *ip6;
892 const struct GNUNET_TUN_UdpHeader *udp;
893 const struct GNUNET_TUN_DnsHeader *dns;
894 struct RequestRecord *rr;
895 struct sockaddr_in *srca4;
896 struct sockaddr_in6 *srca6;
897 struct sockaddr_in *dsta4;
898 struct sockaddr_in6 *dsta6;
900 LOG (GNUNET_ERROR_TYPE_DEBUG,
901 "Intercepted message via DNS hijacker\n");
902 msize = ntohs (message->size);
903 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
905 /* non-IP packet received on TUN!? */
909 msize -= sizeof (struct GNUNET_MessageHeader);
910 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
911 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
912 switch (ntohs (tun->proto))
915 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
916 ip6 = NULL; /* make compiler happy */
917 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
918 (ip4->version != 4) ||
919 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
920 (ntohs(ip4->total_length) != msize) ||
921 (ip4->protocol != IPPROTO_UDP) )
923 /* non-IP/UDP packet received on TUN (or with options) */
924 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
925 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
928 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
929 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
932 ip4 = NULL; /* make compiler happy */
933 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
934 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
935 (ip6->version != 6) ||
936 (ntohs (ip6->payload_length) != msize - sizeof (struct GNUNET_TUN_IPv6Header)) ||
937 (ip6->next_header != IPPROTO_UDP) )
939 /* non-IP/UDP packet received on TUN (or with extensions) */
940 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
941 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
944 udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
945 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
948 /* non-IP packet received on TUN!? */
949 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
950 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
951 (unsigned int) msize,
955 if ( (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) ||
956 (DNS_PORT != ntohs (udp->destination_port)) )
958 /* non-DNS packet received on TUN, ignore */
959 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
960 _("DNS interceptor got non-DNS packet (dropped)\n"));
961 GNUNET_STATISTICS_update (stats,
962 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
966 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
967 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
968 rr = &requests[dns->id];
970 /* clean up from previous request */
971 GNUNET_free_non_null (rr->payload);
973 GNUNET_array_grow (rr->client_wait_list,
974 rr->client_wait_list_length,
977 /* setup new request */
979 switch (ntohs (tun->proto))
983 srca4 = (struct sockaddr_in*) &rr->src_addr;
984 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
985 memset (srca4, 0, sizeof (struct sockaddr_in));
986 memset (dsta4, 0, sizeof (struct sockaddr_in));
987 srca4->sin_family = AF_INET;
988 dsta4->sin_family = AF_INET;
989 srca4->sin_addr = ip4->source_address;
990 dsta4->sin_addr = ip4->destination_address;
991 srca4->sin_port = udp->source_port;
992 dsta4->sin_port = udp->destination_port;
993 #if HAVE_SOCKADDR_IN_SIN_LEN
994 srca4->sin_len = sizeof (struct sockaddr_in);
995 dsta4->sin_len = sizeof (struct sockaddr_in);
1001 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1002 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1003 memset (srca6, 0, sizeof (struct sockaddr_in6));
1004 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1005 srca6->sin6_family = AF_INET6;
1006 dsta6->sin6_family = AF_INET6;
1007 srca6->sin6_addr = ip6->source_address;
1008 dsta6->sin6_addr = ip6->destination_address;
1009 srca6->sin6_port = udp->source_port;
1010 dsta6->sin6_port = udp->destination_port;
1011 #if HAVE_SOCKADDR_IN_SIN_LEN
1012 srca6->sin6_len = sizeof (struct sockaddr_in6);
1013 dsta6->sin6_len = sizeof (struct sockaddr_in6);
1020 rr->payload = GNUNET_malloc (msize);
1021 rr->payload_length = msize;
1022 GNUNET_memcpy (rr->payload, dns, msize);
1023 rr->request_id = dns->id | (request_id_gen << 16);
1025 LOG (GNUNET_ERROR_TYPE_DEBUG,
1026 "Creating new DNS request %llu\n",
1027 (unsigned long long) rr->request_id);
1028 GNUNET_STATISTICS_update (stats,
1029 gettext_noop ("# DNS requests received via TUN interface"),
1031 /* start request processing state machine */
1038 * @param cls closure
1039 * @param cfg_ configuration to use
1040 * @param service the initialized service
1044 const struct GNUNET_CONFIGURATION_Handle *cfg_,
1045 struct GNUNET_SERVICE_Handle *service)
1057 stats = GNUNET_STATISTICS_create ("dns", cfg);
1058 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1060 dnsstub = GNUNET_DNSSTUB_start (128);
1061 /* TODO: support multiple DNS_EXIT servers being configured */
1062 /* TODO: see above TODO on using DNS server from original packet.
1063 Not sure which is best... */
1066 GNUNET_CONFIGURATION_get_value_string (cfg,
1071 GNUNET_DNSSTUB_add_dns_ip (dnsstub,
1074 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1077 _("need a valid IPv4 or IPv6 address\n"));
1078 GNUNET_free_non_null (dns_exit);
1080 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
1082 GNUNET_OS_check_helper_binary (binary,
1084 NULL)) // TODO: once we have a windows-testcase, add test parameters here
1086 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1087 _("`%s' must be installed SUID, will not run DNS interceptor\n"),
1090 GNUNET_free (binary);
1093 GNUNET_free (binary);
1095 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1096 if (GNUNET_SYSERR ==
1097 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1099 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1100 "No entry 'IFNAME' in configuration!\n");
1101 GNUNET_SCHEDULER_shutdown ();
1104 helper_argv[1] = ifc_name;
1105 if ( (GNUNET_SYSERR ==
1106 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1110 "No entry 'IPV6ADDR' in configuration!\n");
1111 GNUNET_SCHEDULER_shutdown ();
1114 helper_argv[2] = ipv6addr;
1115 if (GNUNET_SYSERR ==
1116 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1120 "No entry 'IPV6PREFIX' in configuration!\n");
1121 GNUNET_SCHEDULER_shutdown ();
1124 helper_argv[3] = ipv6prefix;
1126 if (GNUNET_SYSERR ==
1127 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1131 "No entry 'IPV4ADDR' in configuration!\n");
1132 GNUNET_SCHEDULER_shutdown ();
1135 helper_argv[4] = ipv4addr;
1136 if (GNUNET_SYSERR ==
1137 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1141 "No entry 'IPV4MASK' in configuration!\n");
1142 GNUNET_SCHEDULER_shutdown ();
1145 helper_argv[5] = ipv4mask;
1147 nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1148 "SKIP_ROUTING_SETUP");
1149 if (GNUNET_YES == nortsetup)
1150 helper_argv[6] = GNUNET_strdup("1");
1152 helper_argv[6] = GNUNET_strdup("0");
1154 helper_argv[7] = NULL;
1155 hijacker = GNUNET_HELPER_start (GNUNET_NO,
1156 "gnunet-helper-dns",
1158 &process_helper_messages,
1164 * Define "main" method using service macro.
1168 GNUNET_SERVICE_OPTION_NONE,
1171 &client_disconnect_cb,
1173 GNUNET_MQ_hd_fixed_size (client_init,
1174 GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1175 struct GNUNET_DNS_Register,
1177 GNUNET_MQ_hd_var_size (client_response,
1178 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE,
1179 struct GNUNET_DNS_Response,
1181 GNUNET_MQ_handler_end ());
1184 /* FIXME: this might need a port on systems without 'getresgid' */
1187 * Enable use of SGID capabilities on POSIX
1189 void __attribute__ ((constructor))
1196 if (-1 == getresgid (&rgid,
1201 "getresgid failed: %s\n",
1204 else if (sgid != rgid)
1206 if (-1 == setregid (sgid,
1209 "setregid failed: %s\n",
1216 /* end of gnunet-service-dns.c */